]> git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
Fix UI rendering to not use the bouncegrid texture; it looked interesting on the...
[xonotic/darkplaces.git] / r_shadow.c
1 #include "quakedef.h"
2 #include "r_shadow.h"
3 #include "cl_collision.h"
4 #include "portals.h"
5 #include "image.h"
6
7 static void R_Shadow_EditLights_Init(void);
8
9 typedef enum r_shadow_rendermode_e
10 {
11         R_SHADOW_RENDERMODE_NONE,
12         R_SHADOW_RENDERMODE_ZPASS_STENCIL,
13         R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
14         R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
15         R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
16         R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
17         R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
18         R_SHADOW_RENDERMODE_LIGHT_GLSL,
19         R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
20         R_SHADOW_RENDERMODE_VISIBLELIGHTING,
21         R_SHADOW_RENDERMODE_SHADOWMAP2D
22 }
23 r_shadow_rendermode_t;
24
25 typedef enum r_shadow_shadowmode_e
26 {
27         R_SHADOW_SHADOWMODE_SHADOWMAP2D
28 }
29 r_shadow_shadowmode_t;
30
31 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
32 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
33 int r_shadow_scenemaxlights;
34 int r_shadow_scenenumlights;
35 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
36 qboolean r_shadow_usingshadowmap2d;
37 qboolean r_shadow_usingshadowmaportho;
38 int r_shadow_shadowmapside;
39 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
40 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
41 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
42 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
43 #if 0
44 int r_shadow_drawbuffer;
45 int r_shadow_readbuffer;
46 #endif
47 int r_shadow_cullface_front, r_shadow_cullface_back;
48 GLuint r_shadow_fbo2d;
49 r_shadow_shadowmode_t r_shadow_shadowmode;
50 int r_shadow_shadowmapfilterquality;
51 int r_shadow_shadowmapdepthbits;
52 int r_shadow_shadowmapmaxsize;
53 int r_shadow_shadowmaptexturesize;
54 qboolean r_shadow_shadowmapvsdct;
55 qboolean r_shadow_shadowmapsampler;
56 qboolean r_shadow_shadowmapshadowsampler;
57 int r_shadow_shadowmappcf;
58 int r_shadow_shadowmapborder;
59 matrix4x4_t r_shadow_shadowmapmatrix;
60 int r_shadow_lightscissor[4];
61 qboolean r_shadow_usingdeferredprepass;
62 qboolean r_shadow_shadowmapdepthtexture;
63 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
64 int r_shadow_shadowmapatlas_modelshadows_x;
65 int r_shadow_shadowmapatlas_modelshadows_y;
66 int r_shadow_shadowmapatlas_modelshadows_size;
67 int maxshadowtriangles;
68 int *shadowelements;
69
70 int maxshadowvertices;
71 float *shadowvertex3f;
72
73 int maxshadowmark;
74 int numshadowmark;
75 int *shadowmark;
76 int *shadowmarklist;
77 int shadowmarkcount;
78
79 int maxshadowsides;
80 int numshadowsides;
81 unsigned char *shadowsides;
82 int *shadowsideslist;
83
84 int maxvertexupdate;
85 int *vertexupdate;
86 int *vertexremap;
87 int vertexupdatenum;
88
89 int r_shadow_buffer_numleafpvsbytes;
90 unsigned char *r_shadow_buffer_visitingleafpvs;
91 unsigned char *r_shadow_buffer_leafpvs;
92 int *r_shadow_buffer_leaflist;
93
94 int r_shadow_buffer_numsurfacepvsbytes;
95 unsigned char *r_shadow_buffer_surfacepvs;
96 int *r_shadow_buffer_surfacelist;
97 unsigned char *r_shadow_buffer_surfacesides;
98
99 int r_shadow_buffer_numshadowtrispvsbytes;
100 unsigned char *r_shadow_buffer_shadowtrispvs;
101 int r_shadow_buffer_numlighttrispvsbytes;
102 unsigned char *r_shadow_buffer_lighttrispvs;
103
104 rtexturepool_t *r_shadow_texturepool;
105 rtexture_t *r_shadow_attenuationgradienttexture;
106 skinframe_t *r_shadow_lightcorona;
107 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
108 rtexture_t *r_shadow_shadowmap2ddepthtexture;
109 rtexture_t *r_shadow_shadowmapvsdcttexture;
110
111 GLuint r_shadow_prepassgeometryfbo;
112 GLuint r_shadow_prepasslightingdiffusespecularfbo;
113 GLuint r_shadow_prepasslightingdiffusefbo;
114 int r_shadow_prepass_width;
115 int r_shadow_prepass_height;
116 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
117 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
118 rtexture_t *r_shadow_prepasslightingdiffusetexture;
119 rtexture_t *r_shadow_prepasslightingspeculartexture;
120
121 int r_shadow_viewfbo;
122 rtexture_t *r_shadow_viewdepthtexture;
123 rtexture_t *r_shadow_viewcolortexture;
124 int r_shadow_viewx;
125 int r_shadow_viewy;
126 int r_shadow_viewwidth;
127 int r_shadow_viewheight;
128
129 // lights are reloaded when this changes
130 char r_shadow_mapname[MAX_QPATH];
131
132 // buffer for doing corona fading
133 unsigned int r_shadow_occlusion_buf = 0;
134
135 // used only for light filters (cubemaps)
136 rtexturepool_t *r_shadow_filters_texturepool;
137
138 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
139 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
140 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
141 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
142 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
143 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
144 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
145 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
146 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
147 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
148 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
149 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
150 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
151 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
152 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
153 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
154 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
155 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
156 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
157 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
158 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
159 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
160 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
161 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
162 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
163 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
164 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
165 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
166 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
167 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
168 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
169 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
170 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
171 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
172 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
173 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
174 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
175 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
176 cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
177 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
178 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
179 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
180 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
181 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
182 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
183 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
184 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
185 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
186 cvar_t r_shadow_culllights_pvs = {CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
187 cvar_t r_shadow_culllights_trace = {CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
188 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
189 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
190 cvar_t r_shadow_culllights_trace_expand = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
191 cvar_t r_shadow_culllights_trace_pad = {CVAR_SAVE, "r_shadow_culllights_trace_pad", "8", "accept traces that hit within this many units of the light bounds"};
192 cvar_t r_shadow_culllights_trace_samples = {CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
193 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
194 cvar_t r_shadow_culllights_trace_delay = {CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
195 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
196 cvar_t r_shadow_bouncegrid_blur = {CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
197 cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
198 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color" };
199 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "1", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
200 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "1", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
201 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_dlightparticlemultiplier", "1", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
202 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
203 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1)"};
204 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0)"};
205 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by energyperphoton"};
206 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)"};
207 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
208 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
209 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
210 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
211 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
212 cvar_t r_shadow_bouncegrid_floatcolors = {CVAR_SAVE, "r_shadow_bouncegrid_floatcolors", "1", "upload texture as RGBA16F (or RGBA32F when set to 2) rather than RGBA8 format - this gives more dynamic range and accuracy"};
213 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
214 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "1", "overall brightness of bouncegrid texture"};
215 cvar_t r_shadow_bouncegrid_lightpathsize_conespread = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_conespread", "0.015625", "increase lightpathsize over distance at this rate per grid cell"};
216 cvar_t r_shadow_bouncegrid_lightpathsize_initial = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_initial", "0.5", "width (in grid cells) of the light path for accumulation of light in the bouncegrid texture"};
217 cvar_t r_shadow_bouncegrid_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
218 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "2", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
219 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
220 cvar_t r_shadow_bouncegrid_rng_seed = { CVAR_SAVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode" };
221 cvar_t r_shadow_bouncegrid_rng_type = { CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)" };
222 cvar_t r_shadow_bouncegrid_sortlightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_sortlightpaths", "1", "sort light paths before accumulating them into the bouncegrid texture, this reduces cpu cache misses"};
223 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
224 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color" };
225 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
226 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
227 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
228 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
229 cvar_t r_shadow_bouncegrid_static_quality = { CVAR_SAVE, "r_shadow_bouncegrid_static_quality", "16", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)" };
230 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
231 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
232 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
233 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
234 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
235 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
236 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
237 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
238 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
239 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
240 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
241 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
242 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
243 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
244 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
245 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
246 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
247 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
248 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
249 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
250 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
251 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
252 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
253 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
254 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
255 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
256
257 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
258
259 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
260 #define ATTENTABLESIZE 256
261 // 1D gradient, 2D circle and 3D sphere attenuation textures
262 #define ATTEN1DSIZE 32
263 #define ATTEN2DSIZE 64
264 #define ATTEN3DSIZE 32
265
266 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
267 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
268 static float r_shadow_attentable[ATTENTABLESIZE+1];
269
270 rtlight_t *r_shadow_compilingrtlight;
271 static memexpandablearray_t r_shadow_worldlightsarray;
272 dlight_t *r_shadow_selectedlight;
273 dlight_t r_shadow_bufferlight;
274 vec3_t r_editlights_cursorlocation;
275 qboolean r_editlights_lockcursor;
276
277 extern int con_vislines;
278
279 void R_Shadow_UncompileWorldLights(void);
280 void R_Shadow_ClearWorldLights(void);
281 void R_Shadow_SaveWorldLights(void);
282 void R_Shadow_LoadWorldLights(void);
283 void R_Shadow_LoadLightsFile(void);
284 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
285 void R_Shadow_EditLights_Reload_f(void);
286 static void R_Shadow_MakeTextures(void);
287
288 #define EDLIGHTSPRSIZE                  8
289 skinframe_t *r_editlights_sprcursor;
290 skinframe_t *r_editlights_sprlight;
291 skinframe_t *r_editlights_sprnoshadowlight;
292 skinframe_t *r_editlights_sprcubemaplight;
293 skinframe_t *r_editlights_sprcubemapnoshadowlight;
294 skinframe_t *r_editlights_sprselection;
295
296 static void R_Shadow_DrawModelShadowMaps(void);
297 static void R_Shadow_MakeShadowMap(int texturesize);
298 static void R_Shadow_MakeVSDCT(void);
299 static void R_Shadow_SetShadowMode(void)
300 {
301         r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
302         r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
303         r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
304         r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
305         r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
306         r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
307         r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
308         r_shadow_shadowmapsampler = false;
309         r_shadow_shadowmappcf = 0;
310         r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
311         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
312         Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
313         if (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)
314         {
315                 switch(vid.renderpath)
316                 {
317                 case RENDERPATH_GL32:
318                         if(r_shadow_shadowmapfilterquality < 0)
319                         {
320                                 if (!r_fb.usedepthtextures)
321                                         r_shadow_shadowmappcf = 1;
322                                 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
323                                 {
324                                         r_shadow_shadowmapsampler = true;
325                                         r_shadow_shadowmappcf = 1;
326                                 }
327                                 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
328                                         r_shadow_shadowmappcf = 1;
329                                 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
330                                         r_shadow_shadowmappcf = 1;
331                                 else
332                                         r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
333                         }
334                         else
335                         {
336                 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
337                                 switch (r_shadow_shadowmapfilterquality)
338                                 {
339                                 case 1:
340                                         break;
341                                 case 2:
342                                         r_shadow_shadowmappcf = 1;
343                                         break;
344                                 case 3:
345                                         r_shadow_shadowmappcf = 1;
346                                         break;
347                                 case 4:
348                                         r_shadow_shadowmappcf = 2;
349                                         break;
350                                 }
351                         }
352                         if (!r_fb.usedepthtextures)
353                                 r_shadow_shadowmapsampler = false;
354                         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
355                         break;
356                 case RENDERPATH_GLES2:
357                         break;
358                 }
359         }
360
361         if(R_CompileShader_CheckStaticParms())
362                 R_GLSL_Restart_f();
363 }
364
365 qboolean R_Shadow_ShadowMappingEnabled(void)
366 {
367         switch (r_shadow_shadowmode)
368         {
369         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
370                 return true;
371         default:
372                 return false;
373         }
374 }
375
376 static void R_Shadow_FreeShadowMaps(void)
377 {
378         Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
379
380         R_Shadow_SetShadowMode();
381
382         R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
383
384         r_shadow_fbo2d = 0;
385
386         if (r_shadow_shadowmap2ddepthtexture)
387                 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
388         r_shadow_shadowmap2ddepthtexture = NULL;
389
390         if (r_shadow_shadowmap2ddepthbuffer)
391                 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
392         r_shadow_shadowmap2ddepthbuffer = NULL;
393
394         if (r_shadow_shadowmapvsdcttexture)
395                 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
396         r_shadow_shadowmapvsdcttexture = NULL;
397 }
398
399 static void r_shadow_start(void)
400 {
401         // allocate vertex processing arrays
402         memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
403         r_shadow_attenuationgradienttexture = NULL;
404         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
405         r_shadow_shadowmap2ddepthtexture = NULL;
406         r_shadow_shadowmap2ddepthbuffer = NULL;
407         r_shadow_shadowmapvsdcttexture = NULL;
408         r_shadow_shadowmapmaxsize = 0;
409         r_shadow_shadowmaptexturesize = 0;
410         r_shadow_shadowmapfilterquality = -1;
411         r_shadow_shadowmapdepthbits = 0;
412         r_shadow_shadowmapvsdct = false;
413         r_shadow_shadowmapsampler = false;
414         r_shadow_shadowmappcf = 0;
415         r_shadow_fbo2d = 0;
416
417         R_Shadow_FreeShadowMaps();
418
419         r_shadow_texturepool = NULL;
420         r_shadow_filters_texturepool = NULL;
421         R_Shadow_MakeTextures();
422         r_shadow_scenemaxlights = 0;
423         r_shadow_scenenumlights = 0;
424         r_shadow_scenelightlist = NULL;
425         maxshadowtriangles = 0;
426         shadowelements = NULL;
427         maxshadowvertices = 0;
428         shadowvertex3f = NULL;
429         maxvertexupdate = 0;
430         vertexupdate = NULL;
431         vertexremap = NULL;
432         vertexupdatenum = 0;
433         maxshadowmark = 0;
434         numshadowmark = 0;
435         shadowmark = NULL;
436         shadowmarklist = NULL;
437         shadowmarkcount = 0;
438         maxshadowsides = 0;
439         numshadowsides = 0;
440         shadowsides = NULL;
441         shadowsideslist = NULL;
442         r_shadow_buffer_numleafpvsbytes = 0;
443         r_shadow_buffer_visitingleafpvs = NULL;
444         r_shadow_buffer_leafpvs = NULL;
445         r_shadow_buffer_leaflist = NULL;
446         r_shadow_buffer_numsurfacepvsbytes = 0;
447         r_shadow_buffer_surfacepvs = NULL;
448         r_shadow_buffer_surfacelist = NULL;
449         r_shadow_buffer_surfacesides = NULL;
450         r_shadow_buffer_numshadowtrispvsbytes = 0;
451         r_shadow_buffer_shadowtrispvs = NULL;
452         r_shadow_buffer_numlighttrispvsbytes = 0;
453         r_shadow_buffer_lighttrispvs = NULL;
454
455         r_shadow_usingdeferredprepass = false;
456         r_shadow_prepass_width = r_shadow_prepass_height = 0;
457
458         // determine renderpath specific capabilities, we don't need to figure
459         // these out per frame...
460         switch(vid.renderpath)
461         {
462         case RENDERPATH_GL32:
463                 r_shadow_bouncegrid_state.allowdirectionalshading = true;
464                 r_shadow_bouncegrid_state.capable = true;
465                 break;
466         case RENDERPATH_GLES2:
467                 // for performance reasons, do not use directional shading on GLES devices
468                 r_shadow_bouncegrid_state.capable = true;
469                 break;
470         }
471 }
472
473 static void R_Shadow_FreeDeferred(void);
474 static void r_shadow_shutdown(void)
475 {
476         CHECKGLERROR
477         R_Shadow_UncompileWorldLights();
478
479         R_Shadow_FreeShadowMaps();
480
481         r_shadow_usingdeferredprepass = false;
482         if (r_shadow_prepass_width)
483                 R_Shadow_FreeDeferred();
484         r_shadow_prepass_width = r_shadow_prepass_height = 0;
485
486         CHECKGLERROR
487         r_shadow_scenemaxlights = 0;
488         r_shadow_scenenumlights = 0;
489         if (r_shadow_scenelightlist)
490                 Mem_Free(r_shadow_scenelightlist);
491         r_shadow_scenelightlist = NULL;
492         r_shadow_bouncegrid_state.highpixels = NULL;
493         if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
494         if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
495         if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
496         if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
497         if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
498         r_shadow_bouncegrid_state.maxsplatpaths = 0;
499         memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
500         r_shadow_attenuationgradienttexture = NULL;
501         R_FreeTexturePool(&r_shadow_texturepool);
502         R_FreeTexturePool(&r_shadow_filters_texturepool);
503         maxshadowtriangles = 0;
504         if (shadowelements)
505                 Mem_Free(shadowelements);
506         shadowelements = NULL;
507         if (shadowvertex3f)
508                 Mem_Free(shadowvertex3f);
509         shadowvertex3f = NULL;
510         maxvertexupdate = 0;
511         if (vertexupdate)
512                 Mem_Free(vertexupdate);
513         vertexupdate = NULL;
514         if (vertexremap)
515                 Mem_Free(vertexremap);
516         vertexremap = NULL;
517         vertexupdatenum = 0;
518         maxshadowmark = 0;
519         numshadowmark = 0;
520         if (shadowmark)
521                 Mem_Free(shadowmark);
522         shadowmark = NULL;
523         if (shadowmarklist)
524                 Mem_Free(shadowmarklist);
525         shadowmarklist = NULL;
526         shadowmarkcount = 0;
527         maxshadowsides = 0;
528         numshadowsides = 0;
529         if (shadowsides)
530                 Mem_Free(shadowsides);
531         shadowsides = NULL;
532         if (shadowsideslist)
533                 Mem_Free(shadowsideslist);
534         shadowsideslist = NULL;
535         r_shadow_buffer_numleafpvsbytes = 0;
536         if (r_shadow_buffer_visitingleafpvs)
537                 Mem_Free(r_shadow_buffer_visitingleafpvs);
538         r_shadow_buffer_visitingleafpvs = NULL;
539         if (r_shadow_buffer_leafpvs)
540                 Mem_Free(r_shadow_buffer_leafpvs);
541         r_shadow_buffer_leafpvs = NULL;
542         if (r_shadow_buffer_leaflist)
543                 Mem_Free(r_shadow_buffer_leaflist);
544         r_shadow_buffer_leaflist = NULL;
545         r_shadow_buffer_numsurfacepvsbytes = 0;
546         if (r_shadow_buffer_surfacepvs)
547                 Mem_Free(r_shadow_buffer_surfacepvs);
548         r_shadow_buffer_surfacepvs = NULL;
549         if (r_shadow_buffer_surfacelist)
550                 Mem_Free(r_shadow_buffer_surfacelist);
551         r_shadow_buffer_surfacelist = NULL;
552         if (r_shadow_buffer_surfacesides)
553                 Mem_Free(r_shadow_buffer_surfacesides);
554         r_shadow_buffer_surfacesides = NULL;
555         r_shadow_buffer_numshadowtrispvsbytes = 0;
556         if (r_shadow_buffer_shadowtrispvs)
557                 Mem_Free(r_shadow_buffer_shadowtrispvs);
558         r_shadow_buffer_numlighttrispvsbytes = 0;
559         if (r_shadow_buffer_lighttrispvs)
560                 Mem_Free(r_shadow_buffer_lighttrispvs);
561 }
562
563 static void r_shadow_newmap(void)
564 {
565         r_shadow_bouncegrid_state.highpixels = NULL;
566         if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
567         if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
568         if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
569         if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
570         if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
571
572         r_shadow_bouncegrid_state.maxsplatpaths = 0;
573
574         if (r_shadow_bouncegrid_state.texture)    { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
575         if (r_shadow_lightcorona)                 { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
576         if (r_editlights_sprcursor)               { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
577         if (r_editlights_sprlight)                { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
578         if (r_editlights_sprnoshadowlight)        { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
579         if (r_editlights_sprcubemaplight)         { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
580         if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
581         if (r_editlights_sprselection)            { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
582         if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
583                 R_Shadow_EditLights_Reload_f();
584 }
585
586 void R_Shadow_Init(void)
587 {
588         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
589         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
590         Cvar_RegisterVariable(&r_shadow_usebihculling);
591         Cvar_RegisterVariable(&r_shadow_usenormalmap);
592         Cvar_RegisterVariable(&r_shadow_debuglight);
593         Cvar_RegisterVariable(&r_shadow_deferred);
594         Cvar_RegisterVariable(&r_shadow_gloss);
595         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
596         Cvar_RegisterVariable(&r_shadow_glossintensity);
597         Cvar_RegisterVariable(&r_shadow_glossexponent);
598         Cvar_RegisterVariable(&r_shadow_gloss2exponent);
599         Cvar_RegisterVariable(&r_shadow_glossexact);
600         Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
601         Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
602         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
603         Cvar_RegisterVariable(&r_shadow_lightradiusscale);
604         Cvar_RegisterVariable(&r_shadow_projectdistance);
605         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
606         Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
607         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
608         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
609         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
610         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
611         Cvar_RegisterVariable(&r_shadow_realtime_world);
612         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
613         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
614         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
615         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
616         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
617         Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
618         Cvar_RegisterVariable(&r_shadow_scissor);
619         Cvar_RegisterVariable(&r_shadow_shadowmapping);
620         Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
621         Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
622         Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
623         Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
624         Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
625         Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
626         Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
627         Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
628 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
629 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
630         Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
631         Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
632         Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
633         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
634         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
635         Cvar_RegisterVariable(&r_shadow_sortsurfaces);
636         Cvar_RegisterVariable(&r_shadow_culllights_pvs);
637         Cvar_RegisterVariable(&r_shadow_culllights_trace);
638         Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
639         Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
640         Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
641         Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
642         Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
643         Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
644         Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
645         Cvar_RegisterVariable(&r_shadow_bouncegrid);
646         Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
647         Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
648         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
649         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
650         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
651         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
652         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
653         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
654         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
655         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
656         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
657         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
658         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
659         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
660         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
661         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
662         Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
663         Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
664         Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
665         Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
666         Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
667         Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
668         Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
669         Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
670         Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
671         Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
672         Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
673         Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
674         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
675         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
676         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
677         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
678         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
679         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
680         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
681         Cvar_RegisterVariable(&r_coronas);
682         Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
683         Cvar_RegisterVariable(&r_coronas_occlusionquery);
684         Cvar_RegisterVariable(&gl_flashblend);
685         R_Shadow_EditLights_Init();
686         Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
687         r_shadow_scenemaxlights = 0;
688         r_shadow_scenenumlights = 0;
689         r_shadow_scenelightlist = NULL;
690         maxshadowtriangles = 0;
691         shadowelements = NULL;
692         maxshadowvertices = 0;
693         shadowvertex3f = NULL;
694         maxvertexupdate = 0;
695         vertexupdate = NULL;
696         vertexremap = NULL;
697         vertexupdatenum = 0;
698         maxshadowmark = 0;
699         numshadowmark = 0;
700         shadowmark = NULL;
701         shadowmarklist = NULL;
702         shadowmarkcount = 0;
703         maxshadowsides = 0;
704         numshadowsides = 0;
705         shadowsides = NULL;
706         shadowsideslist = NULL;
707         r_shadow_buffer_numleafpvsbytes = 0;
708         r_shadow_buffer_visitingleafpvs = NULL;
709         r_shadow_buffer_leafpvs = NULL;
710         r_shadow_buffer_leaflist = NULL;
711         r_shadow_buffer_numsurfacepvsbytes = 0;
712         r_shadow_buffer_surfacepvs = NULL;
713         r_shadow_buffer_surfacelist = NULL;
714         r_shadow_buffer_surfacesides = NULL;
715         r_shadow_buffer_shadowtrispvs = NULL;
716         r_shadow_buffer_lighttrispvs = NULL;
717         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
718 }
719
720 matrix4x4_t matrix_attenuationxyz =
721 {
722         {
723                 {0.5, 0.0, 0.0, 0.5},
724                 {0.0, 0.5, 0.0, 0.5},
725                 {0.0, 0.0, 0.5, 0.5},
726                 {0.0, 0.0, 0.0, 1.0}
727         }
728 };
729
730 matrix4x4_t matrix_attenuationz =
731 {
732         {
733                 {0.0, 0.0, 0.5, 0.5},
734                 {0.0, 0.0, 0.0, 0.5},
735                 {0.0, 0.0, 0.0, 0.5},
736                 {0.0, 0.0, 0.0, 1.0}
737         }
738 };
739
740 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
741 {
742         numvertices = ((numvertices + 255) & ~255) * vertscale;
743         numtriangles = ((numtriangles + 255) & ~255) * triscale;
744         // make sure shadowelements is big enough for this volume
745         if (maxshadowtriangles < numtriangles)
746         {
747                 maxshadowtriangles = numtriangles;
748                 if (shadowelements)
749                         Mem_Free(shadowelements);
750                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
751         }
752         // make sure shadowvertex3f is big enough for this volume
753         if (maxshadowvertices < numvertices)
754         {
755                 maxshadowvertices = numvertices;
756                 if (shadowvertex3f)
757                         Mem_Free(shadowvertex3f);
758                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
759         }
760 }
761
762 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
763 {
764         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
765         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
766         int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
767         int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
768         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
769         {
770                 if (r_shadow_buffer_visitingleafpvs)
771                         Mem_Free(r_shadow_buffer_visitingleafpvs);
772                 if (r_shadow_buffer_leafpvs)
773                         Mem_Free(r_shadow_buffer_leafpvs);
774                 if (r_shadow_buffer_leaflist)
775                         Mem_Free(r_shadow_buffer_leaflist);
776                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
777                 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
778                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
779                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
780         }
781         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
782         {
783                 if (r_shadow_buffer_surfacepvs)
784                         Mem_Free(r_shadow_buffer_surfacepvs);
785                 if (r_shadow_buffer_surfacelist)
786                         Mem_Free(r_shadow_buffer_surfacelist);
787                 if (r_shadow_buffer_surfacesides)
788                         Mem_Free(r_shadow_buffer_surfacesides);
789                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
790                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
791                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
792                 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
793         }
794         if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
795         {
796                 if (r_shadow_buffer_shadowtrispvs)
797                         Mem_Free(r_shadow_buffer_shadowtrispvs);
798                 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
799                 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
800         }
801         if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
802         {
803                 if (r_shadow_buffer_lighttrispvs)
804                         Mem_Free(r_shadow_buffer_lighttrispvs);
805                 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
806                 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
807         }
808 }
809
810 void R_Shadow_PrepareShadowMark(int numtris)
811 {
812         // make sure shadowmark is big enough for this volume
813         if (maxshadowmark < numtris)
814         {
815                 maxshadowmark = numtris;
816                 if (shadowmark)
817                         Mem_Free(shadowmark);
818                 if (shadowmarklist)
819                         Mem_Free(shadowmarklist);
820                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
821                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
822                 shadowmarkcount = 0;
823         }
824         shadowmarkcount++;
825         // if shadowmarkcount wrapped we clear the array and adjust accordingly
826         if (shadowmarkcount == 0)
827         {
828                 shadowmarkcount = 1;
829                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
830         }
831         numshadowmark = 0;
832 }
833
834 void R_Shadow_PrepareShadowSides(int numtris)
835 {
836         if (maxshadowsides < numtris)
837         {
838                 maxshadowsides = numtris;
839                 if (shadowsides)
840                         Mem_Free(shadowsides);
841                 if (shadowsideslist)
842                         Mem_Free(shadowsideslist);
843                 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
844                 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
845         }
846         numshadowsides = 0;
847 }
848
849 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
850 {
851         // p1, p2, p3 are in the cubemap's local coordinate system
852         // bias = border/(size - border)
853         int mask = 0x3F;
854
855         float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
856                   dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
857                   dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
858         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
859                 mask &= (3<<4)
860                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
861                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
862                         | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
863         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
864                 mask &= (3<<4)
865                         | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
866                         | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))                    
867                         | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
868
869         dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
870         dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
871         dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
872         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
873                 mask &= (3<<0)
874                         | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
875                         | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))                    
876                         | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
877         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
878                 mask &= (3<<0)
879                         | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
880                         | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
881                         | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
882
883         dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
884         dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
885         dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
886         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
887                 mask &= (3<<2)
888                         | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
889                         | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
890                         | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
891         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
892                 mask &= (3<<2)
893                         | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
894                         | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
895                         | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
896
897         return mask;
898 }
899
900 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
901 {
902         vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
903         float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
904         int mask = 0x3F;
905
906         VectorSubtract(maxs, mins, radius);
907         VectorScale(radius, 0.5f, radius);
908         VectorAdd(mins, radius, center);
909         Matrix4x4_Transform(worldtolight, center, lightcenter);
910         Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
911         VectorSubtract(lightcenter, lightradius, pmin);
912         VectorAdd(lightcenter, lightradius, pmax);
913
914         dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
915         dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
916         if(ap1 > bias*an1 && ap2 > bias*an2)
917                 mask &= (3<<4)
918                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
919                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
920         if(an1 > bias*ap1 && an2 > bias*ap2)
921                 mask &= (3<<4)
922                         | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
923                         | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
924
925         dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
926         dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
927         if(ap1 > bias*an1 && ap2 > bias*an2)
928                 mask &= (3<<0)
929                         | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
930                         | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
931         if(an1 > bias*ap1 && an2 > bias*ap2)
932                 mask &= (3<<0)
933                         | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
934                         | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
935
936         dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
937         dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
938         if(ap1 > bias*an1 && ap2 > bias*an2)
939                 mask &= (3<<2)
940                         | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
941                         | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
942         if(an1 > bias*ap1 && an2 > bias*ap2)
943                 mask &= (3<<2)
944                         | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
945                         | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
946
947         return mask;
948 }
949
950 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
951
952 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
953 {
954         // p is in the cubemap's local coordinate system
955         // bias = border/(size - border)
956         float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
957         float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
958         float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
959         int mask = 0x3F;
960         if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
961         if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
962         if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
963         if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
964         if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
965         if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
966         return mask;
967 }
968
969 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
970 {
971         int i;
972         vec3_t o, p, n;
973         int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
974         float scale = (size - 2*border)/size, len;
975         float bias = border / (float)(size - border), dp, dn, ap, an;
976         // check if cone enclosing side would cross frustum plane
977         scale = 2 / (scale*scale + 2);
978         Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
979         for (i = 0;i < 5;i++)
980         {
981                 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
982                         continue;
983                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
984                 len = scale*VectorLength2(n);
985                 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
986                 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
987                 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
988         }
989         if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
990         {
991                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
992                 len = scale*VectorLength2(n);
993                 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
994                 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
995                 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
996         }
997         // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
998         // check if frustum corners/origin cross plane sides
999 #if 1
1000         // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1001         Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1002         dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1003         masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1004         masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1005         dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1006         masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1007         masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1008         dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1009         masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1010         masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1011         for (i = 0;i < 4;i++)
1012         {
1013                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1014                 VectorSubtract(n, p, n);
1015                 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1016                 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1017                 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1018                 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1019                 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1020                 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1021                 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1022                 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1023                 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1024         }
1025 #else
1026         // finite version, assumes corners are a finite distance from origin dependent on far plane
1027         for (i = 0;i < 5;i++)
1028         {
1029                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1030                 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1031                 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1032                 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1033                 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1034                 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1035                 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1036                 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1037                 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1038                 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1039         }
1040 #endif
1041         return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1042 }
1043
1044 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1045 {
1046         int t, tend;
1047         const int *e;
1048         const float *v[3];
1049         float normal[3];
1050         vec3_t p[3];
1051         float bias;
1052         int mask, surfacemask = 0;
1053         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1054                 return 0;
1055         bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1056         tend = firsttriangle + numtris;
1057         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1058         {
1059                 // surface box entirely inside light box, no box cull
1060                 if (projectdirection)
1061                 {
1062                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1063                         {
1064                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1065                                 TriangleNormal(v[0], v[1], v[2], normal);
1066                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1067                                 {
1068                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1069                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1070                                         surfacemask |= mask;
1071                                         if(totals)
1072                                         {
1073                                                 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1074                                                 shadowsides[numshadowsides] = mask;
1075                                                 shadowsideslist[numshadowsides++] = t;
1076                                         }
1077                                 }
1078                         }
1079                 }
1080                 else
1081                 {
1082                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1083                         {
1084                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1085                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1086                                 {
1087                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1088                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1089                                         surfacemask |= mask;
1090                                         if(totals)
1091                                         {
1092                                                 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1093                                                 shadowsides[numshadowsides] = mask;
1094                                                 shadowsideslist[numshadowsides++] = t;
1095                                         }
1096                                 }
1097                         }
1098                 }
1099         }
1100         else
1101         {
1102                 // surface box not entirely inside light box, cull each triangle
1103                 if (projectdirection)
1104                 {
1105                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1106                         {
1107                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1108                                 TriangleNormal(v[0], v[1], v[2], normal);
1109                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1110                                  && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1111                                 {
1112                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1113                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1114                                         surfacemask |= mask;
1115                                         if(totals)
1116                                         {
1117                                                 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1118                                                 shadowsides[numshadowsides] = mask;
1119                                                 shadowsideslist[numshadowsides++] = t;
1120                                         }
1121                                 }
1122                         }
1123                 }
1124                 else
1125                 {
1126                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1127                         {
1128                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1129                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1130                                  && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1131                                 {
1132                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1133                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1134                                         surfacemask |= mask;
1135                                         if(totals)
1136                                         {
1137                                                 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1138                                                 shadowsides[numshadowsides] = mask;
1139                                                 shadowsideslist[numshadowsides++] = t;
1140                                         }
1141                                 }
1142                         }
1143                 }
1144         }
1145         return surfacemask;
1146 }
1147
1148 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1149 {
1150         int i, j, outtriangles = 0;
1151         int *outelement3i[6];
1152         if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1153                 return;
1154         outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1155         // make sure shadowelements is big enough for this mesh
1156         if (maxshadowtriangles < outtriangles)
1157                 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1158
1159         // compute the offset and size of the separate index lists for each cubemap side
1160         outtriangles = 0;
1161         for (i = 0;i < 6;i++)
1162         {
1163                 outelement3i[i] = shadowelements + outtriangles * 3;
1164                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1165                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1166                 outtriangles += sidetotals[i];
1167         }
1168
1169         // gather up the (sparse) triangles into separate index lists for each cubemap side
1170         for (i = 0;i < numsidetris;i++)
1171         {
1172                 const int *element = elements + sidetris[i] * 3;
1173                 for (j = 0;j < 6;j++)
1174                 {
1175                         if (sides[i] & (1 << j))
1176                         {
1177                                 outelement3i[j][0] = element[0];
1178                                 outelement3i[j][1] = element[1];
1179                                 outelement3i[j][2] = element[2];
1180                                 outelement3i[j] += 3;
1181                         }
1182                 }
1183         }
1184
1185         Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1186 }
1187
1188 static void R_Shadow_MakeTextures_MakeCorona(void)
1189 {
1190         float dx, dy;
1191         int x, y, a;
1192         unsigned char pixels[32][32][4];
1193         for (y = 0;y < 32;y++)
1194         {
1195                 dy = (y - 15.5f) * (1.0f / 16.0f);
1196                 for (x = 0;x < 32;x++)
1197                 {
1198                         dx = (x - 15.5f) * (1.0f / 16.0f);
1199                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1200                         a = bound(0, a, 255);
1201                         pixels[y][x][0] = a;
1202                         pixels[y][x][1] = a;
1203                         pixels[y][x][2] = a;
1204                         pixels[y][x][3] = 255;
1205                 }
1206         }
1207         r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1208 }
1209
1210 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1211 {
1212         float dist = sqrt(x*x+y*y+z*z);
1213         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1214         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1215         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1216 }
1217
1218 static void R_Shadow_MakeTextures(void)
1219 {
1220         int x;
1221         float intensity, dist;
1222         unsigned int *data;
1223         R_Shadow_FreeShadowMaps();
1224         R_FreeTexturePool(&r_shadow_texturepool);
1225         r_shadow_texturepool = R_AllocTexturePool();
1226         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1227         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1228         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1229         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1230         for (x = 0;x <= ATTENTABLESIZE;x++)
1231         {
1232                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1233                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1234                 r_shadow_attentable[x] = bound(0, intensity, 1);
1235         }
1236         // 1D gradient texture
1237         for (x = 0;x < ATTEN1DSIZE;x++)
1238                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1239         r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1240         Mem_Free(data);
1241
1242         R_Shadow_MakeTextures_MakeCorona();
1243
1244         // Editor light sprites
1245         r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1246         "................"
1247         ".3............3."
1248         "..5...2332...5.."
1249         "...7.3....3.7..."
1250         "....7......7...."
1251         "...3.7....7.3..."
1252         "..2...7..7...2.."
1253         "..3..........3.."
1254         "..3..........3.."
1255         "..2...7..7...2.."
1256         "...3.7....7.3..."
1257         "....7......7...."
1258         "...7.3....3.7..."
1259         "..5...2332...5.."
1260         ".3............3."
1261         "................"
1262         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1263         r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1264         "................"
1265         "................"
1266         "......1111......"
1267         "....11233211...."
1268         "...1234554321..."
1269         "...1356776531..."
1270         "..124677776421.."
1271         "..135777777531.."
1272         "..135777777531.."
1273         "..124677776421.."
1274         "...1356776531..."
1275         "...1234554321..."
1276         "....11233211...."
1277         "......1111......"
1278         "................"
1279         "................"
1280         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1281         r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1282         "................"
1283         "................"
1284         "......1111......"
1285         "....11233211...."
1286         "...1234554321..."
1287         "...1356226531..."
1288         "..12462..26421.."
1289         "..1352....2531.."
1290         "..1352....2531.."
1291         "..12462..26421.."
1292         "...1356226531..."
1293         "...1234554321..."
1294         "....11233211...."
1295         "......1111......"
1296         "................"
1297         "................"
1298         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1299         r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1300         "................"
1301         "................"
1302         "......2772......"
1303         "....27755772...."
1304         "..277533335772.."
1305         "..753333333357.."
1306         "..777533335777.."
1307         "..735775577537.."
1308         "..733357753337.."
1309         "..733337733337.."
1310         "..753337733357.."
1311         "..277537735772.."
1312         "....27777772...."
1313         "......2772......"
1314         "................"
1315         "................"
1316         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1317         r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1318         "................"
1319         "................"
1320         "......2772......"
1321         "....27722772...."
1322         "..2772....2772.."
1323         "..72........27.."
1324         "..7772....2777.."
1325         "..7.27722772.7.."
1326         "..7...2772...7.."
1327         "..7....77....7.."
1328         "..72...77...27.."
1329         "..2772.77.2772.."
1330         "....27777772...."
1331         "......2772......"
1332         "................"
1333         "................"
1334         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1335         r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1336         "................"
1337         ".777752..257777."
1338         ".742........247."
1339         ".72..........27."
1340         ".7............7."
1341         ".5............5."
1342         ".2............2."
1343         "................"
1344         "................"
1345         ".2............2."
1346         ".5............5."
1347         ".7............7."
1348         ".72..........27."
1349         ".742........247."
1350         ".777752..257777."
1351         "................"
1352         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1353 }
1354
1355 void R_Shadow_RenderMode_Begin(void)
1356 {
1357 #if 0
1358         GLint drawbuffer;
1359         GLint readbuffer;
1360 #endif
1361
1362         if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1363          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1364                 R_Shadow_MakeTextures();
1365
1366         CHECKGLERROR
1367         R_Mesh_ResetTextureState();
1368         GL_BlendFunc(GL_ONE, GL_ZERO);
1369         GL_DepthRange(0, 1);
1370         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1371         GL_DepthTest(true);
1372         GL_DepthMask(false);
1373         GL_Color(0, 0, 0, 1);
1374         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1375         
1376         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1377         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1378
1379         CHECKGLERROR
1380 #if 0
1381         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1382         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1383         r_shadow_drawbuffer = drawbuffer;
1384         r_shadow_readbuffer = readbuffer;
1385 #endif
1386         r_shadow_cullface_front = r_refdef.view.cullface_front;
1387         r_shadow_cullface_back = r_refdef.view.cullface_back;
1388 }
1389
1390 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1391 {
1392         rsurface.rtlight = rtlight;
1393 }
1394
1395 void R_Shadow_RenderMode_Reset(void)
1396 {
1397         R_Mesh_ResetTextureState();
1398         R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1399         R_SetViewport(&r_refdef.view.viewport);
1400         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1401         GL_DepthRange(0, 1);
1402         GL_DepthTest(true);
1403         GL_DepthMask(false);
1404         GL_DepthFunc(GL_LEQUAL);
1405         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1406         r_refdef.view.cullface_front = r_shadow_cullface_front;
1407         r_refdef.view.cullface_back = r_shadow_cullface_back;
1408         GL_CullFace(r_refdef.view.cullface_back);
1409         GL_Color(1, 1, 1, 1);
1410         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1411         GL_BlendFunc(GL_ONE, GL_ZERO);
1412         R_SetupShader_Generic_NoTexture(false, false);
1413         r_shadow_usingshadowmap2d = false;
1414 }
1415
1416 void R_Shadow_ClearStencil(void)
1417 {
1418         GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1419         r_refdef.stats[r_stat_lights_clears]++;
1420 }
1421
1422 static void R_Shadow_MakeVSDCT(void)
1423 {
1424         // maps to a 2x3 texture rectangle with normalized coordinates
1425         // +-
1426         // XX
1427         // YY
1428         // ZZ
1429         // stores abs(dir.xy), offset.xy/2.5
1430         unsigned char data[4*6] =
1431         {
1432                 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1433                 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1434                 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1435                 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1436                 0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1437                 0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1438         };
1439         r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1440 }
1441
1442 static void R_Shadow_MakeShadowMap(int texturesize)
1443 {
1444         switch (r_shadow_shadowmode)
1445         {
1446         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1447                 if (r_shadow_shadowmap2ddepthtexture) return;
1448                 if (r_fb.usedepthtextures)
1449                 {
1450                         r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), r_shadow_shadowmapsampler);
1451                         r_shadow_shadowmap2ddepthbuffer = NULL;
1452                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1453                 }
1454                 else
1455                 {
1456                         r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1457                         r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1458                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1459                 }
1460                 break;
1461         default:
1462                 return;
1463         }
1464 }
1465
1466 void R_Shadow_ClearShadowMapTexture(void)
1467 {
1468         r_viewport_t viewport;
1469         float clearcolor[4];
1470
1471         // if they don't exist, create our textures now
1472         if (!r_shadow_shadowmap2ddepthtexture)
1473                 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1474         if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1475                 R_Shadow_MakeVSDCT();
1476
1477         // we're setting up to render shadowmaps, so change rendermode
1478         r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1479
1480         R_Mesh_ResetTextureState();
1481         R_Shadow_RenderMode_Reset();
1482         if (r_shadow_shadowmap2ddepthbuffer)
1483                 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1484         else
1485                 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1486         R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1487         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1488         GL_DepthMask(true);
1489         GL_DepthTest(true);
1490
1491         // we have to set a viewport to clear anything in some renderpaths (D3D)
1492         R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1493         R_SetViewport(&viewport);
1494         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1495         if (r_shadow_shadowmap2ddepthbuffer)
1496                 GL_ColorMask(1, 1, 1, 1);
1497         else
1498                 GL_ColorMask(0, 0, 0, 0);
1499         switch (vid.renderpath)
1500         {
1501         case RENDERPATH_GL32:
1502         case RENDERPATH_GLES2:
1503                 GL_CullFace(r_refdef.view.cullface_back);
1504                 break;
1505         }
1506         Vector4Set(clearcolor, 1, 1, 1, 1);
1507         if (r_shadow_shadowmap2ddepthbuffer)
1508                 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1509         else
1510                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1511 }
1512
1513 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1514 {
1515         int size = rsurface.rtlight->shadowmapatlassidesize;
1516         float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1517         float farclip = 1.0f;
1518         float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1519         r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1520         r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1521         r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1522         r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1523         r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1524         r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1525         r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1526         r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1527         if (r_shadow_shadowmap2ddepthbuffer)
1528         {
1529                 // completely different meaning than in depthtexture approach
1530                 r_shadow_lightshadowmap_parameters[1] = 0;
1531                 r_shadow_lightshadowmap_parameters[3] = -bias;
1532         }
1533 }
1534
1535 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1536 {
1537         float nearclip, farclip, bias;
1538         r_viewport_t viewport;
1539         int flipped;
1540         float clearcolor[4];
1541
1542         if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1543         {
1544                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1545
1546                 R_Mesh_ResetTextureState();
1547                 R_Shadow_RenderMode_Reset();
1548                 if (r_shadow_shadowmap2ddepthbuffer)
1549                         R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1550                 else
1551                         R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1552                 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1553                 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1554                 GL_DepthMask(true);
1555                 GL_DepthTest(true);
1556         }
1557
1558         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1559         farclip = 1.0f;
1560         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1561
1562         R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1563         R_SetViewport(&viewport);
1564         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1565         flipped = (side & 1) ^ (side >> 2);
1566         r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1567         r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1568
1569         Vector4Set(clearcolor, 1,1,1,1);
1570         if (r_shadow_shadowmap2ddepthbuffer)
1571                 GL_ColorMask(1,1,1,1);
1572         else
1573                 GL_ColorMask(0,0,0,0);
1574         switch(vid.renderpath)
1575         {
1576         case RENDERPATH_GL32:
1577         case RENDERPATH_GLES2:
1578                 GL_CullFace(r_refdef.view.cullface_back);
1579                 break;
1580         }
1581
1582         // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1583         r_shadow_shadowmapside = side;
1584 }
1585
1586 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1587 {
1588         R_Mesh_ResetTextureState();
1589         if (transparent)
1590         {
1591                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1592                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1593                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1594                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1595         }
1596         if (shadowmapping)
1597                 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1598         R_Shadow_RenderMode_Reset();
1599         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1600         if (!transparent)
1601                 GL_DepthFunc(GL_EQUAL);
1602         // do global setup needed for the chosen lighting mode
1603         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1604                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1605         r_shadow_usingshadowmap2d = shadowmapping;
1606         r_shadow_rendermode = r_shadow_lightingrendermode;
1607 }
1608
1609 static const unsigned short bboxelements[36] =
1610 {
1611         5, 1, 3, 5, 3, 7,
1612         6, 2, 0, 6, 0, 4,
1613         7, 3, 2, 7, 2, 6,
1614         4, 0, 1, 4, 1, 5,
1615         4, 5, 7, 4, 7, 6,
1616         1, 0, 2, 1, 2, 3,
1617 };
1618
1619 static const float bboxpoints[8][3] =
1620 {
1621         {-1,-1,-1},
1622         { 1,-1,-1},
1623         {-1, 1,-1},
1624         { 1, 1,-1},
1625         {-1,-1, 1},
1626         { 1,-1, 1},
1627         {-1, 1, 1},
1628         { 1, 1, 1},
1629 };
1630
1631 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1632 {
1633         int i;
1634         float vertex3f[8*3];
1635         const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1636 // do global setup needed for the chosen lighting mode
1637         R_Shadow_RenderMode_Reset();
1638         r_shadow_rendermode = r_shadow_lightingrendermode;
1639         R_EntityMatrix(&identitymatrix);
1640         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1641         if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1642                 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1643         else
1644                 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1645
1646         r_shadow_usingshadowmap2d = shadowmapping;
1647
1648         // render the lighting
1649         R_SetupShader_DeferredLight(rsurface.rtlight);
1650         for (i = 0;i < 8;i++)
1651                 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1652         GL_ColorMask(1,1,1,1);
1653         GL_DepthMask(false);
1654         GL_DepthRange(0, 1);
1655         GL_PolygonOffset(0, 0);
1656         GL_DepthTest(true);
1657         GL_DepthFunc(GL_GREATER);
1658         GL_CullFace(r_refdef.view.cullface_back);
1659         R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1660         R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1661 }
1662
1663 #define MAXBOUNCEGRIDSPLATSIZE 7
1664 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
1665
1666 // these are temporary data per-frame, sorted and performed in a more
1667 // cache-friendly order than the original photons
1668 typedef struct r_shadow_bouncegrid_splatpath_s
1669 {
1670         vec3_t point;
1671         vec3_t step;
1672         vec3_t splatcolor;
1673         vec3_t splatdir;
1674         vec_t splatintensity;
1675         vec_t splatsize_current;
1676         vec_t splatsize_perstep;
1677         int remainingsplats;
1678 }
1679 r_shadow_bouncegrid_splatpath_t;
1680
1681 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
1682 {
1683         int bestaxis;
1684         int numsplats;
1685         float len;
1686         float ilen;
1687         vec3_t start;
1688         vec3_t end;
1689         vec3_t diff;
1690         vec3_t originaldir;
1691         r_shadow_bouncegrid_splatpath_t *path;
1692
1693         // cull paths that fail R_CullBox in dynamic mode
1694         if (!r_shadow_bouncegrid_state.settings.staticmode
1695          && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
1696         {
1697                 vec3_t cullmins, cullmaxs;
1698                 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
1699                 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
1700                 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
1701                 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
1702                 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
1703                 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
1704                 if (R_CullBox(cullmins, cullmaxs))
1705                         return;
1706         }
1707
1708         // if the light path is going upward, reverse it - we always draw down.
1709         if (originalend[2] < originalstart[2])
1710         {
1711                 VectorCopy(originalend, start);
1712                 VectorCopy(originalstart, end);
1713         }
1714         else
1715         {
1716                 VectorCopy(originalstart, start);
1717                 VectorCopy(originalend, end);
1718         }
1719
1720         // transform to texture pixels
1721         start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1722         start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1723         start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1724         end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1725         end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1726         end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1727
1728         // check if we need to grow the splatpaths array
1729         if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
1730         {
1731                 // double the limit, this will persist from frame to frame so we don't
1732                 // make the same mistake each time
1733                 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
1734                 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
1735                         r_shadow_bouncegrid_state.maxsplatpaths = 16384;
1736                 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.splatpaths, sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
1737         }
1738
1739         // divide a series of splats along the length using the maximum axis
1740         VectorSubtract(end, start, diff);
1741         // pick the best axis to trace along
1742         bestaxis = 0;
1743         if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
1744                 bestaxis = 1;
1745         if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
1746                 bestaxis = 2;
1747         len = fabs(diff[bestaxis]);
1748         ilen = 1.0f / len;
1749         numsplats = (int)(floor(len + 0.5f));
1750         // sanity limits
1751         numsplats = bound(0, numsplats, 1024);
1752
1753         VectorSubtract(originalstart, originalend, originaldir);
1754         VectorNormalize(originaldir);
1755
1756         path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
1757         VectorCopy(start, path->point);
1758         VectorScale(diff, ilen, path->step);
1759         VectorCopy(color, path->splatcolor);
1760         VectorCopy(originaldir, path->splatdir);
1761         path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
1762         path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
1763         path->splatintensity = VectorLength(color);
1764         path->remainingsplats = numsplats;
1765 }
1766
1767 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1768 {
1769         qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1770         int lightindex;
1771         int range;
1772         dlight_t *light;
1773         rtlight_t *rtlight;
1774         vec3_t lightcolor;
1775
1776         // see if there are really any lights to render...
1777         if (enable && r_shadow_bouncegrid_static.integer)
1778         {
1779                 enable = false;
1780                 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1781                 for (lightindex = 0;lightindex < range;lightindex++)
1782                 {
1783                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1784                         if (!light || !(light->flags & flag))
1785                                 continue;
1786                         rtlight = &light->rtlight;
1787                         // when static, we skip styled lights because they tend to change...
1788                         if (rtlight->style > 0)
1789                                 continue;
1790                         VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1791                         if (!VectorLength2(lightcolor))
1792                                 continue;
1793                         enable = true;
1794                         break;
1795                 }
1796         }
1797
1798         return enable;
1799 }
1800
1801 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1802 {
1803         qboolean s = r_shadow_bouncegrid_static.integer != 0;
1804         float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1805         float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1806         float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1807
1808         // prevent any garbage in alignment padded areas as we'll be using memcmp
1809         memset(settings, 0, sizeof(*settings));
1810
1811         // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1812         settings->staticmode                    = s;
1813         settings->blur                          = r_shadow_bouncegrid_blur.integer != 0;
1814         settings->floatcolors                   = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1815         settings->lightpathsize_initial         = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
1816         settings->lightpathsize_conespread      = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
1817         settings->bounceanglediffuse            = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
1818         settings->directionalshading            = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1819         settings->dlightparticlemultiplier      = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1820         settings->hitmodels                     = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1821         settings->includedirectlighting         = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1822         settings->lightradiusscale              = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1823         settings->maxbounce                     = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1824         settings->particlebounceintensity       = r_shadow_bouncegrid_particlebounceintensity.value;
1825         settings->particleintensity             = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
1826         settings->maxphotons                    = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1827         settings->energyperphoton               = spacing * spacing / quality;
1828         settings->spacing[0]                    = spacing;
1829         settings->spacing[1]                    = spacing;
1830         settings->spacing[2]                    = spacing;
1831         settings->rng_type                      = r_shadow_bouncegrid_rng_type.integer;
1832         settings->rng_seed                      = r_shadow_bouncegrid_rng_seed.integer;
1833         settings->bounceminimumintensity2       = bounceminimumintensity * bounceminimumintensity;
1834         settings->bounceminimumintensity2       = bounceminimumintensity * bounceminimumintensity;
1835         settings->normalizevectors              = r_shadow_bouncegrid_normalizevectors.integer != 0;
1836
1837         // bound the values for sanity
1838         settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1839         settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1840         settings->maxbounce = bound(0, settings->maxbounce, 16);
1841         settings->spacing[0] = bound(1, settings->spacing[0], 512);
1842         settings->spacing[1] = bound(1, settings->spacing[1], 512);
1843         settings->spacing[2] = bound(1, settings->spacing[2], 512);
1844 }
1845
1846 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1847 {
1848         float m[16];
1849         int c[4];
1850         int resolution[3];
1851         int numpixels;
1852         vec3_t ispacing;
1853         vec3_t maxs;
1854         vec3_t mins;
1855         vec3_t size;
1856         vec3_t spacing;
1857         r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1858
1859         // get the spacing values
1860         spacing[0] = settings->spacing[0];
1861         spacing[1] = settings->spacing[1];
1862         spacing[2] = settings->spacing[2];
1863         ispacing[0] = 1.0f / spacing[0];
1864         ispacing[1] = 1.0f / spacing[1];
1865         ispacing[2] = 1.0f / spacing[2];
1866
1867         // calculate texture size enclosing entire world bounds at the spacing
1868         if (r_refdef.scene.worldmodel)
1869         {
1870                 int lightindex;
1871                 int range;
1872                 qboolean bounds_set = false;
1873                 dlight_t *light;
1874                 rtlight_t *rtlight;
1875
1876                 // calculate bounds enclosing world lights as they should be noticably tighter 
1877                 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1878                 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1879                 for (lightindex = 0;lightindex < range;lightindex++)
1880                 {
1881                         const vec_t *rtlmins, *rtlmaxs;
1882
1883                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1884                         if (!light)
1885                                 continue;
1886
1887                         rtlight = &light->rtlight;
1888                         rtlmins = rtlight->cullmins;
1889                         rtlmaxs = rtlight->cullmaxs;
1890
1891                         if (!bounds_set)
1892                         {
1893                                 VectorCopy(rtlmins, mins);
1894                                 VectorCopy(rtlmaxs, maxs);
1895                                 bounds_set = true;
1896                         }
1897                         else
1898                         {
1899                                 mins[0] = min(mins[0], rtlmins[0]);
1900                                 mins[1] = min(mins[1], rtlmins[1]);
1901                                 mins[2] = min(mins[2], rtlmins[2]);
1902                                 maxs[0] = max(maxs[0], rtlmaxs[0]);
1903                                 maxs[1] = max(maxs[1], rtlmaxs[1]);
1904                                 maxs[2] = max(maxs[2], rtlmaxs[2]);
1905                         }
1906                 }
1907
1908                 // limit to no larger than the world bounds
1909                 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1910                 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1911                 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1912                 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1913                 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1914                 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1915
1916                 VectorMA(mins, -2.0f, spacing, mins);
1917                 VectorMA(maxs, 2.0f, spacing, maxs);
1918         }
1919         else
1920         {
1921                 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1922                 VectorSet(maxs,  1048576.0f,  1048576.0f,  1048576.0f);
1923         }
1924         VectorSubtract(maxs, mins, size);
1925         // now we can calculate the resolution we want
1926         c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1927         c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1928         c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1929         // figure out the exact texture size (honoring power of 2 if required)
1930         resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1931         resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1932         resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1933         size[0] = spacing[0] * resolution[0];
1934         size[1] = spacing[1] * resolution[1];
1935         size[2] = spacing[2] * resolution[2];
1936
1937         // if dynamic we may or may not want to use the world bounds
1938         // if the dynamic size is smaller than the world bounds, use it instead
1939         if (!settings->staticmode && (r_shadow_bouncegrid_dynamic_x.integer * r_shadow_bouncegrid_dynamic_y.integer * r_shadow_bouncegrid_dynamic_z.integer < resolution[0] * resolution[1] * resolution[2]))
1940         {
1941                 // we know the resolution we want
1942                 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1943                 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1944                 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1945                 // now we can calculate the texture size
1946                 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1947                 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1948                 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1949                 size[0] = spacing[0] * resolution[0];
1950                 size[1] = spacing[1] * resolution[1];
1951                 size[2] = spacing[2] * resolution[2];
1952                 // center the rendering on the view
1953                 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1954                 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1955                 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1956         }
1957
1958         // recalculate the maxs in case the resolution was not satisfactory
1959         VectorAdd(mins, size, maxs);
1960
1961         // check if this changed the texture size
1962         r_shadow_bouncegrid_state.createtexture = !(r_shadow_bouncegrid_state.texture && r_shadow_bouncegrid_state.resolution[0] == resolution[0] && r_shadow_bouncegrid_state.resolution[1] == resolution[1] && r_shadow_bouncegrid_state.resolution[2] == resolution[2] && r_shadow_bouncegrid_state.directional == r_shadow_bouncegrid_state.settings.directionalshading);
1963         r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1964         VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1965         VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1966         VectorCopy(size, r_shadow_bouncegrid_state.size);
1967         VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1968         VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1969         VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1970
1971         // reallocate pixels for this update if needed...
1972         r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1973         r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1974         r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1975         numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1976         if (r_shadow_bouncegrid_state.numpixels != numpixels)
1977         {
1978                 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1979
1980                 r_shadow_bouncegrid_state.highpixels = NULL;
1981
1982                 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1983                 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1984                 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1985                 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1986                 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
1987
1988                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
1989                 r_shadow_bouncegrid_state.numpixels = numpixels;
1990         }
1991
1992         // update the bouncegrid matrix to put it in the world properly
1993         memset(m, 0, sizeof(m));
1994         m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1995         m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1996         m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1997         m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1998         m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1999         m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2000         m[15] = 1.0f;
2001         Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2002 }
2003
2004 // enumerate world rtlights and sum the overall amount of light in the world,
2005 // from that we can calculate a scaling factor to fairly distribute photons
2006 // to all the lights
2007 //
2008 // this modifies rtlight->photoncolor and rtlight->photons
2009 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2010 {
2011         float normalphotonscaling;
2012         float photonscaling;
2013         float photonintensity;
2014         float photoncount = 0.0f;
2015         float lightintensity;
2016         float radius;
2017         float s;
2018         float w;
2019         vec3_t cullmins;
2020         vec3_t cullmaxs;
2021         unsigned int lightindex;
2022         dlight_t *light;
2023         rtlight_t *rtlight;
2024         normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2025         for (lightindex = 0;lightindex < range2;lightindex++)
2026         {
2027                 if (lightindex < range)
2028                 {
2029                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2030                         if (!light)
2031                                 continue;
2032                         rtlight = &light->rtlight;
2033                         VectorClear(rtlight->bouncegrid_photoncolor);
2034                         rtlight->bouncegrid_photons = 0;
2035                         rtlight->bouncegrid_hits = 0;
2036                         rtlight->bouncegrid_traces = 0;
2037                         rtlight->bouncegrid_effectiveradius = 0;
2038                         if (!(light->flags & flag))
2039                                 continue;
2040                         if (settings->staticmode)
2041                         {
2042                                 // when static, we skip styled lights because they tend to change...
2043                                 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2044                                         continue;
2045                         }
2046                         else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2047                                 continue;
2048                 }
2049                 else
2050                 {
2051                         rtlight = r_refdef.scene.lights[lightindex - range];
2052                         VectorClear(rtlight->bouncegrid_photoncolor);
2053                         rtlight->bouncegrid_photons = 0;
2054                         rtlight->bouncegrid_hits = 0;
2055                         rtlight->bouncegrid_traces = 0;
2056                         rtlight->bouncegrid_effectiveradius = 0;
2057                 }
2058                 // draw only visible lights (major speedup)
2059                 radius = rtlight->radius * settings->lightradiusscale;
2060                 cullmins[0] = rtlight->shadoworigin[0] - radius;
2061                 cullmins[1] = rtlight->shadoworigin[1] - radius;
2062                 cullmins[2] = rtlight->shadoworigin[2] - radius;
2063                 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2064                 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2065                 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2066                 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2067                 if (!settings->staticmode)
2068                 {
2069                         // skip if the expanded light box does not touch any visible leafs
2070                         if (r_refdef.scene.worldmodel
2071                                 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2072                                 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2073                                 continue;
2074                         // skip if the expanded light box is not visible to traceline
2075                         // note that PrepareLight already did this check but for a smaller box, so we
2076                         // end up casting more traces per frame per light when using bouncegrid, which
2077                         // is probably fine (and they use the same timer)
2078                         if (r_shadow_culllights_trace.integer)
2079                         {
2080                                 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
2081                                         rtlight->trace_timer = realtime;
2082                                 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2083                                         continue;
2084                         }
2085                         // skip if expanded light box is offscreen
2086                         if (R_CullBox(cullmins, cullmaxs))
2087                                 continue;
2088                         // skip if overall light intensity is zero
2089                         if (w * VectorLength2(rtlight->color) == 0.0f)
2090                                 continue;
2091                 }
2092                 // a light that does not emit any light before style is applied, can be
2093                 // skipped entirely (it may just be a corona)
2094                 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2095                         continue;
2096                 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2097                 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2098                 // skip lights that will emit no photons
2099                 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2100                         continue;
2101                 // shoot particles from this light
2102                 // use a calculation for the number of particles that will not
2103                 // vary with lightstyle, otherwise we get randomized particle
2104                 // distribution, the seeded random is only consistent for a
2105                 // consistent number of particles on this light...
2106                 s = rtlight->radius;
2107                 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2108                 if (lightindex >= range)
2109                         lightintensity *= settings->dlightparticlemultiplier;
2110                 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2111                 photoncount += rtlight->bouncegrid_photons;
2112                 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2113                 // if the lightstyle happens to be off right now, we can skip actually
2114                 // firing the photons, but we did have to count them in the total.
2115                 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2116                 //      rtlight->bouncegrid_photons = 0;
2117         }
2118         // the user provided an energyperphoton value which we try to use
2119         // if that results in too many photons to shoot this frame, then we cap it
2120         // which causes photons to appear/disappear from frame to frame, so we don't
2121         // like doing that in the typical case
2122         photonscaling = 1.0f;
2123         photonintensity = 1.0f;
2124         if (photoncount > settings->maxphotons)
2125         {
2126                 photonscaling = settings->maxphotons / photoncount;
2127                 photonintensity = 1.0f / photonscaling;
2128         }
2129
2130         // modify the lights to reflect our computed scaling
2131         for (lightindex = 0; lightindex < range2; lightindex++)
2132         {
2133                 if (lightindex < range)
2134                 {
2135                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2136                         if (!light)
2137                                 continue;
2138                         rtlight = &light->rtlight;
2139                 }
2140                 else
2141                         rtlight = r_refdef.scene.lights[lightindex - range];
2142                 rtlight->bouncegrid_photons *= photonscaling;
2143                 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2144         }
2145 }
2146
2147 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2148 {
2149         r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2150         r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2151         // we only really care about sorting by Z
2152         if (a->point[2] < b->point[2])
2153                 return -1;
2154         if (a->point[2] > b->point[2])
2155                 return 1;
2156         return 0;
2157 }
2158
2159 static void R_Shadow_BounceGrid_ClearPixels(void)
2160 {
2161         // clear the highpixels array we'll be accumulating into
2162         if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2163                 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2164         if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2165                 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2166         r_shadow_bouncegrid_state.highpixels_index = 0;
2167         r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2168         memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2169 }
2170
2171 static void R_Shadow_BounceGrid_PerformSplats(void)
2172 {
2173         r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2174         r_shadow_bouncegrid_splatpath_t *splatpath;
2175         float *highpixels = r_shadow_bouncegrid_state.highpixels;
2176         int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2177         int splatindex;
2178         vec3_t steppos;
2179         vec3_t stepdelta;
2180         vec3_t dir;
2181         vec_t lightpathsize_current;
2182         vec_t lightpathsize_perstep;
2183         float splatcolor[32];
2184         int resolution[3];
2185         int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2186         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2187         int numsteps;
2188         int step;
2189
2190         // hush warnings about uninitialized data - pixelbands doesn't change but...
2191         memset(splatcolor, 0, sizeof(splatcolor));
2192
2193         // we use this a lot, so get a local copy
2194         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2195
2196         // sort the splats before we execute them, to reduce cache misses
2197         if (r_shadow_bouncegrid_sortlightpaths.integer)
2198                 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2199
2200         splatpath = splatpaths;
2201         for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2202         {
2203                 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2204                 // accumulate average shotcolor
2205                 VectorCopy(splatpath->splatdir, dir);
2206                 splatcolor[ 0] = splatpath->splatcolor[0];
2207                 splatcolor[ 1] = splatpath->splatcolor[1];
2208                 splatcolor[ 2] = splatpath->splatcolor[2];
2209                 splatcolor[ 3] = 0.0f;
2210                 if (pixelbands > 1)
2211                 {
2212                         // store bentnormal in case the shader has a use for it,
2213                         // bentnormal is an intensity-weighted average of the directions,
2214                         // and will be normalized on conversion to texture pixels.
2215                         splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2216                         splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2217                         splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2218                         splatcolor[ 7] = splatpath->splatintensity;
2219                         // for each color component (R, G, B) calculate the amount that a
2220                         // direction contributes
2221                         splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2222                         splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2223                         splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2224                         splatcolor[11] = 0.0f;
2225                         splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2226                         splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2227                         splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2228                         splatcolor[15] = 0.0f;
2229                         splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2230                         splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2231                         splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2232                         splatcolor[19] = 0.0f;
2233                         // and do the same for negative directions
2234                         splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2235                         splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2236                         splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2237                         splatcolor[23] = 0.0f;
2238                         splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2239                         splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2240                         splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2241                         splatcolor[27] = 0.0f;
2242                         splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2243                         splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2244                         splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2245                         splatcolor[31] = 0.0f;
2246                 }
2247                 // calculate the number of steps we need to traverse this distance
2248                 VectorCopy(splatpath->point, steppos);
2249                 VectorCopy(splatpath->step, stepdelta);
2250                 numsteps = splatpath->remainingsplats;
2251                 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
2252                 lightpathsize_perstep = splatpath->splatsize_perstep;
2253                 for (step = 0;step < numsteps;step++)
2254                 {
2255                         // the middle row/column/layer of each splat are full intensity
2256                         float splatmins[3];
2257                         float splatmaxs[3];
2258                         if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
2259                                 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
2260                         splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
2261                         splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
2262                         splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
2263                         splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
2264                         splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
2265                         splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
2266                         if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
2267                         {
2268                                 // it is within bounds...  do the real work now
2269                                 int xi, yi, zi, band, row;
2270                                 float pixelpos[3];
2271                                 float w;
2272                                 float *p;
2273                                 float colorscale = 1.0f / lightpathsize_current;
2274                                 r_refdef.stats[r_stat_bouncegrid_splats]++;
2275                                 // accumulate light onto the pixels
2276                                 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
2277                                 {
2278                                         pixelpos[2] = zi + 0.5f;
2279                                         for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
2280                                         {
2281                                                 pixelpos[1] = yi + 0.5f;
2282                                                 row = (zi*resolution[1] + yi)*resolution[0];
2283                                                 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
2284                                                 {
2285                                                         pixelpos[0] = xi + 0.5f;
2286                                                         // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
2287                                                         w = lightpathsize_current - VectorDistance(pixelpos, steppos);
2288                                                         if (w > 0.0f)
2289                                                         {
2290                                                                 if (w > 1.0f)
2291                                                                         w = 1.0f;
2292                                                                 w *= colorscale;
2293                                                                 p = highpixels + 4 * (row + xi);
2294                                                                 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
2295                                                                 {
2296                                                                         // add to the pixel color
2297                                                                         p[0] += splatcolor[band * 4 + 0] * w;
2298                                                                         p[1] += splatcolor[band * 4 + 1] * w;
2299                                                                         p[2] += splatcolor[band * 4 + 2] * w;
2300                                                                         p[3] += splatcolor[band * 4 + 3] * w;
2301                                                                 }
2302                                                         }
2303                                                 }
2304                                         }
2305                                 }
2306                         }
2307                         VectorAdd(steppos, stepdelta, steppos);
2308                         lightpathsize_current += lightpathsize_perstep;
2309                 }
2310         }
2311 }
2312
2313 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2314 {
2315         const float *inpixel;
2316         float *outpixel;
2317         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2318         int pixelband;
2319         unsigned int index;
2320         unsigned int x, y, z;
2321         unsigned int resolution[3];
2322         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2323         for (pixelband = 0;pixelband < pixelbands;pixelband++)
2324         {
2325                 for (z = 1;z < resolution[2]-1;z++)
2326                 {
2327                         for (y = 1;y < resolution[1]-1;y++)
2328                         {
2329                                 x = 1;
2330                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2331                                 inpixel = inpixels + 4*index;
2332                                 outpixel = outpixels + 4*index;
2333                                 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2334                                 {
2335                                         outpixel[0] = (inpixel[0] + inpixel[  off] + inpixel[0-off]) * (1.0f / 3.0);
2336                                         outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2337                                         outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2338                                         outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2339                                 }
2340                         }
2341                 }
2342         }
2343 }
2344
2345 static void R_Shadow_BounceGrid_BlurPixels(void)
2346 {
2347         float *pixels[4];
2348         unsigned int resolution[3];
2349
2350         if (!r_shadow_bouncegrid_state.settings.blur)
2351                 return;
2352         
2353         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2354
2355         pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2356         pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2357         pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2358         pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2359
2360         // blur on X
2361         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2362         // blur on Y
2363         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2364         // blur on Z
2365         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2366
2367         // toggle the state, highpixels now points to pixels[3] result
2368         r_shadow_bouncegrid_state.highpixels_index ^= 1;
2369         r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2370 }
2371
2372 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2373 {
2374         int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2375         unsigned char *pixelsbgra8 = NULL;
2376         unsigned char *pixelbgra8;
2377         unsigned short *pixelsrgba16f = NULL;
2378         unsigned short *pixelrgba16f;
2379         float *pixelsrgba32f = NULL;
2380         float *highpixels = r_shadow_bouncegrid_state.highpixels;
2381         float *highpixel;
2382         float *bandpixel;
2383         unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2384         unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2385         unsigned int pixelband;
2386         unsigned int x, y, z;
2387         unsigned int index, bandindex;
2388         unsigned int resolution[3];
2389         int c[4];
2390         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2391
2392         if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2393         {
2394                 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2395                 r_shadow_bouncegrid_state.texture = NULL;
2396         }
2397
2398         // if bentnormals exist, we need to normalize and bias them for the shader
2399         if (pixelbands > 1)
2400         {
2401                 pixelband = 1;
2402                 for (z = 0;z < resolution[2]-1;z++)
2403                 {
2404                         for (y = 0;y < resolution[1]-1;y++)
2405                         {
2406                                 x = 1;
2407                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2408                                 highpixel = highpixels + 4*index;
2409                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2410                                 {
2411                                         // only convert pixels that were hit by photons
2412                                         if (highpixel[3] != 0.0f)
2413                                                 VectorNormalize(highpixel);
2414                                         VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2415                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
2416                                 }
2417                         }
2418                 }
2419         }
2420
2421         // start by clearing the pixels array - we won't be writing to all of it
2422         //
2423         // then process only the pixels that have at least some color, skipping
2424         // the higher bands for speed on pixels that are black
2425         switch (floatcolors)
2426         {
2427         case 0:
2428                 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2429                         r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2430                 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2431                 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2432                 {
2433                         if (pixelband == 1)
2434                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2435                         else
2436                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2437                 }
2438                 for (z = 1;z < resolution[2]-1;z++)
2439                 {
2440                         for (y = 1;y < resolution[1]-1;y++)
2441                         {
2442                                 x = 1;
2443                                 pixelband = 0;
2444                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2445                                 highpixel = highpixels + 4*index;
2446                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2447                                 {
2448                                         // only convert pixels that were hit by photons
2449                                         if (VectorLength2(highpixel))
2450                                         {
2451                                                 // normalize the bentnormal now
2452                                                 if (pixelbands > 1)
2453                                                 {
2454                                                         VectorNormalize(highpixel + pixelsperband * 4);
2455                                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
2456                                                 }
2457                                                 // process all of the pixelbands for this pixel
2458                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2459                                                 {
2460                                                         pixelbgra8 = pixelsbgra8 + 4*bandindex;
2461                                                         bandpixel = highpixels + 4*bandindex;
2462                                                         c[0] = (int)(bandpixel[0]*256.0f);
2463                                                         c[1] = (int)(bandpixel[1]*256.0f);
2464                                                         c[2] = (int)(bandpixel[2]*256.0f);
2465                                                         c[3] = (int)(bandpixel[3]*256.0f);
2466                                                         pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2467                                                         pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2468                                                         pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2469                                                         pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2470                                                 }
2471                                         }
2472                                 }
2473                         }
2474                 }
2475
2476                 if (!r_shadow_bouncegrid_state.createtexture)
2477                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2478                 else
2479                         r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixelsbgra8, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2480                 break;
2481         case 1:
2482                 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2483                         r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2484                 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2485                 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2486                 for (z = 1;z < resolution[2]-1;z++)
2487                 {
2488                         for (y = 1;y < resolution[1]-1;y++)
2489                         {
2490                                 x = 1;
2491                                 pixelband = 0;
2492                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2493                                 highpixel = highpixels + 4*index;
2494                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2495                                 {
2496                                         // only convert pixels that were hit by photons
2497                                         if (VectorLength2(highpixel))
2498                                         {
2499                                                 // process all of the pixelbands for this pixel
2500                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2501                                                 {
2502                                                         // time to have fun with IEEE 754 bit hacking...
2503                                                         union {
2504                                                                 float f[4];
2505                                                                 unsigned int raw[4];
2506                                                         } u;
2507                                                         pixelrgba16f = pixelsrgba16f + 4*bandindex;
2508                                                         bandpixel = highpixels + 4*bandindex;
2509                                                         VectorCopy4(bandpixel, u.f);
2510                                                         VectorCopy4(u.raw, c);
2511                                                         // this math supports negative numbers, snaps denormals to zero
2512                                                         //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2513                                                         //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2514                                                         //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2515                                                         //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2516                                                         // this math does not support negative
2517                                                         pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2518                                                         pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2519                                                         pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2520                                                         pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2521                                                 }
2522                                         }
2523                                 }
2524                         }
2525                 }
2526
2527                 if (!r_shadow_bouncegrid_state.createtexture)
2528                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2529                 else
2530                         r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, (const unsigned char *)pixelsrgba16f, TEXTYPE_COLORBUFFER16F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2531                 break;
2532         case 2:
2533                 // our native format happens to match, so this is easy.
2534                 pixelsrgba32f = highpixels;
2535
2536                 if (!r_shadow_bouncegrid_state.createtexture)
2537                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2538                 else
2539                         r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, (const unsigned char *)pixelsrgba32f, TEXTYPE_COLORBUFFER32F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2540                 break;
2541         }
2542
2543         r_shadow_bouncegrid_state.lastupdatetime = realtime;
2544 }
2545
2546 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2547 {
2548         vec3_t bouncerandom[10];
2549         dlight_t *light;
2550         int bouncecount;
2551         int hitsupercontentsmask;
2552         int skipsupercontentsmask;
2553         int skipmaterialflagsmask;
2554         int maxbounce;
2555         int shootparticles;
2556         int shotparticles;
2557         float bounceminimumintensity2;
2558         trace_t cliptrace;
2559         //trace_t cliptrace2;
2560         //trace_t cliptrace3;
2561         unsigned int lightindex;
2562         unsigned int seed;
2563         randomseed_t randomseed;
2564         vec3_t shotcolor;
2565         vec3_t baseshotcolor;
2566         vec3_t surfcolor;
2567         vec3_t clipend;
2568         vec3_t clipstart;
2569         vec3_t clipdiff;
2570         vec_t radius;
2571         vec_t distancetraveled;
2572         vec_t s;
2573         rtlight_t *rtlight;
2574
2575         // compute a seed for the unstable random modes
2576         Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2577         seed = realtime * 1000.0;
2578
2579         r_shadow_bouncegrid_state.numsplatpaths = 0;
2580
2581         // figure out what we want to interact with
2582         if (settings.hitmodels)
2583                 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2584         else
2585                 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2586         skipsupercontentsmask = 0;
2587         skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
2588         maxbounce = settings.maxbounce;
2589
2590         for (lightindex = 0;lightindex < range2;lightindex++)
2591         {
2592                 if (lightindex < range)
2593                 {
2594                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2595                         if (!light)
2596                                 continue;
2597                         rtlight = &light->rtlight;
2598                 }
2599                 else
2600                         rtlight = r_refdef.scene.lights[lightindex - range];
2601                 // note that this code used to keep track of residual photons and
2602                 // distribute them evenly to achieve exactly a desired photon count,
2603                 // but that caused unwanted flickering in dynamic mode
2604                 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2605                 // skip if we won't be shooting any photons
2606                 if (!shootparticles)
2607                         continue;
2608                 radius = rtlight->radius * settings.lightradiusscale;
2609                 //s = settings.particleintensity / shootparticles;
2610                 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2611                 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2612                 if (VectorLength2(baseshotcolor) <= 0.0f)
2613                         continue;
2614                 r_refdef.stats[r_stat_bouncegrid_lights]++;
2615                 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2616                 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2617                 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
2618
2619                 // for seeded random we start the RNG with the position of the light
2620                 if (settings.rng_seed >= 0)
2621                 {
2622                         union
2623                         {
2624                                 unsigned int i[4];
2625                                 float f[4];
2626                         }
2627                         u;
2628                         u.f[0] = rtlight->shadoworigin[0];
2629                         u.f[1] = rtlight->shadoworigin[1];
2630                         u.f[2] = rtlight->shadoworigin[2];
2631                         u.f[3] = 1;
2632                         switch (settings.rng_type)
2633                         {
2634                         default:
2635                         case 0:
2636                                 // we have to shift the seed provided by the user because the result must be odd
2637                                 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
2638                                 break;
2639                         case 1:
2640                                 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
2641                                 break;
2642                         }
2643                 }
2644
2645                 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2646                 {
2647                         VectorCopy(baseshotcolor, shotcolor);
2648                         VectorCopy(rtlight->shadoworigin, clipstart);
2649                         switch (settings.rng_type)
2650                         {
2651                         default:
2652                         case 0:
2653                                 VectorLehmerRandom(&randomseed, clipend);
2654                                 if (settings.bounceanglediffuse)
2655                                 {
2656                                         // we want random to be stable, so we still have to do all the random we would have done
2657                                         for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2658                                                 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
2659                                 }
2660                                 break;
2661                         case 1:
2662                                 VectorCheeseRandom(seed, clipend);
2663                                 if (settings.bounceanglediffuse)
2664                                 {
2665                                         // we want random to be stable, so we still have to do all the random we would have done
2666                                         for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2667                                                 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
2668                                 }
2669                                 break;
2670                         }
2671
2672                         // we want a uniform distribution spherically, not merely within the sphere
2673                         if (settings.normalizevectors)
2674                                 VectorNormalize(clipend);
2675
2676                         VectorMA(clipstart, radius, clipend, clipend);
2677                         distancetraveled = 0.0f;
2678                         for (bouncecount = 0;;bouncecount++)
2679                         {
2680                                 r_refdef.stats[r_stat_bouncegrid_traces]++;
2681                                 rtlight->bouncegrid_traces++;
2682                                 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2683                                 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2684                                 if (settings.staticmode || settings.rng_seed < 0)
2685                                 {
2686                                         // static mode fires a LOT of rays but none of them are identical, so they are not cached
2687                                         // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2688                                         cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, true, true);
2689                                 }
2690                                 else
2691                                 {
2692                                         // dynamic mode fires many rays and most will match the cache from the previous frame
2693                                         cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2694                                 }
2695                                 if (bouncecount > 0 || settings.includedirectlighting)
2696                                 {
2697                                         vec3_t hitpos;
2698                                         VectorCopy(cliptrace.endpos, hitpos);
2699                                         R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
2700                                 }
2701                                 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
2702                                 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
2703                                 if (rtlight->bouncegrid_effectiveradius < s)
2704                                         rtlight->bouncegrid_effectiveradius = s;
2705                                 if (cliptrace.fraction >= 1.0f)
2706                                         break;
2707                                 r_refdef.stats[r_stat_bouncegrid_hits]++;
2708                                 rtlight->bouncegrid_hits++;
2709                                 if (bouncecount >= maxbounce)
2710                                         break;
2711                                 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2712                                 // also clamp the resulting color to never add energy, even if the user requests extreme values
2713                                 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2714                                         VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2715                                 else
2716                                         VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2717                                 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2718                                 surfcolor[0] = min(surfcolor[0], 1.0f);
2719                                 surfcolor[1] = min(surfcolor[1], 1.0f);
2720                                 surfcolor[2] = min(surfcolor[2], 1.0f);
2721                                 VectorMultiply(shotcolor, surfcolor, shotcolor);
2722                                 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
2723                                         break;
2724                                 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2725                                 if (settings.bounceanglediffuse)
2726                                 {
2727                                         // random direction, primarily along plane normal
2728                                         s = VectorDistance(cliptrace.endpos, clipend);
2729                                         VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
2730                                         VectorNormalize(clipend);
2731                                         VectorScale(clipend, s, clipend);
2732                                 }
2733                                 else
2734                                 {
2735                                         // reflect the remaining portion of the line across plane normal
2736                                         VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2737                                         VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2738                                 }
2739                                 // calculate the new line start and end
2740                                 VectorCopy(cliptrace.endpos, clipstart);
2741                                 VectorAdd(clipstart, clipend, clipend);
2742                         }
2743                 }
2744         }
2745 }
2746
2747 void R_Shadow_UpdateBounceGridTexture(void)
2748 {
2749         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2750         r_shadow_bouncegrid_settings_t settings;
2751         qboolean enable = false;
2752         qboolean settingschanged;
2753         unsigned int range; // number of world lights
2754         unsigned int range1; // number of dynamic lights (or zero if disabled)
2755         unsigned int range2; // range+range1
2756
2757         enable = R_Shadow_BounceGrid_CheckEnable(flag);
2758         
2759         R_Shadow_BounceGrid_GenerateSettings(&settings);
2760         
2761         // changing intensity does not require an update
2762         r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2763
2764         settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2765
2766         // when settings change, we free everything as it is just simpler that way.
2767         if (settingschanged || !enable)
2768         {
2769                 // not enabled, make sure we free anything we don't need anymore.
2770                 if (r_shadow_bouncegrid_state.texture)
2771                 {
2772                         R_FreeTexture(r_shadow_bouncegrid_state.texture);
2773                         r_shadow_bouncegrid_state.texture = NULL;
2774                 }
2775                 r_shadow_bouncegrid_state.highpixels = NULL;
2776                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2777                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2778                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2779                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2780                 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2781                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2782                 r_shadow_bouncegrid_state.numpixels = 0;
2783                 r_shadow_bouncegrid_state.directional = false;
2784
2785                 if (!enable)
2786                         return;
2787         }
2788
2789         // if all the settings seem identical to the previous update, return
2790         if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2791                 return;
2792
2793         // store the new settings
2794         r_shadow_bouncegrid_state.settings = settings;
2795
2796         R_Shadow_BounceGrid_UpdateSpacing();
2797
2798         // get the range of light numbers we'll be looping over:
2799         // range = static lights
2800         // range1 = dynamic lights (optional)
2801         // range2 = range + range1
2802         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2803         range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2804         range2 = range + range1;
2805
2806         // calculate weighting factors for distributing photons among the lights
2807         R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
2808         R_TimeReport("bouncegrid_assignphotons");
2809
2810         // trace the photons from lights and accumulate illumination
2811         R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
2812         R_TimeReport("bouncegrid_tracephotons");
2813
2814         // clear the texture
2815         R_Shadow_BounceGrid_ClearPixels();
2816         R_TimeReport("bouncegrid_cleartex");
2817
2818         // accumulate the light splatting into texture
2819         R_Shadow_BounceGrid_PerformSplats();
2820         R_TimeReport("bouncegrid_lighttex");
2821
2822         // apply a mild blur filter to the texture
2823         R_Shadow_BounceGrid_BlurPixels();
2824         R_TimeReport("bouncegrid_blurtex");
2825
2826         // convert the pixels to lower precision and upload the texture
2827         R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2828         R_TimeReport("bouncegrid_uploadtex");
2829
2830         // after we compute the static lighting we don't need to keep the highpixels array around
2831         if (settings.staticmode)
2832         {
2833                 r_shadow_bouncegrid_state.highpixels = NULL;
2834                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2835                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2836                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2837                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2838                 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2839                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2840         }
2841 }
2842
2843 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2844 {
2845         R_Shadow_RenderMode_Reset();
2846         GL_BlendFunc(GL_ONE, GL_ONE);
2847         GL_DepthRange(0, 1);
2848         GL_DepthTest(r_showlighting.integer < 2);
2849         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2850         if (!transparent)
2851                 GL_DepthFunc(GL_EQUAL);
2852         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2853 }
2854
2855 void R_Shadow_RenderMode_End(void)
2856 {
2857         R_Shadow_RenderMode_Reset();
2858         R_Shadow_RenderMode_ActiveLight(NULL);
2859         GL_DepthMask(true);
2860         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2861         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2862 }
2863
2864 int bboxedges[12][2] =
2865 {
2866         // top
2867         {0, 1}, // +X
2868         {0, 2}, // +Y
2869         {1, 3}, // Y, +X
2870         {2, 3}, // X, +Y
2871         // bottom
2872         {4, 5}, // +X
2873         {4, 6}, // +Y
2874         {5, 7}, // Y, +X
2875         {6, 7}, // X, +Y
2876         // verticals
2877         {0, 4}, // +Z
2878         {1, 5}, // X, +Z
2879         {2, 6}, // Y, +Z
2880         {3, 7}, // XY, +Z
2881 };
2882
2883 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2884 {
2885         if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2886         {
2887                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2888                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2889                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2890                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2891                 return false;
2892         }
2893         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2894                 return true; // invisible
2895         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2896         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2897         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2898         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2899                 r_refdef.stats[r_stat_lights_scissored]++;
2900         return false;
2901 }
2902
2903 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2904 {
2905         // used to display how many times a surface is lit for level design purposes
2906         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2907         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2908         RSurf_DrawBatch();
2909 }
2910
2911 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3], const float specularcolor[3])
2912 {
2913         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2914         R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2915         RSurf_DrawBatch();
2916 }
2917
2918 extern cvar_t gl_lightmaps;
2919 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2920 {
2921         qboolean negated;
2922         float ambientcolor[3], diffusecolor[3], specularcolor[3];
2923         VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2924         VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2925         VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2926         if (!r_shadow_usenormalmap.integer)
2927         {
2928                 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2929                 VectorClear(diffusecolor);
2930                 VectorClear(specularcolor);
2931         }
2932         VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2933         VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2934         VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2935         if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2936                 return;
2937         negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2938         if(negated)
2939         {
2940                 VectorNegate(ambientcolor, ambientcolor);
2941                 VectorNegate(diffusecolor, diffusecolor);
2942                 VectorNegate(specularcolor, specularcolor);
2943                 GL_BlendEquationSubtract(true);
2944         }
2945         RSurf_SetupDepthAndCulling();
2946         switch (r_shadow_rendermode)
2947         {
2948         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2949                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2950                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2951                 break;
2952         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2953                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2954                 break;
2955         default:
2956                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2957                 break;
2958         }
2959         if(negated)
2960                 GL_BlendEquationSubtract(false);
2961 }
2962
2963 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2964 {
2965         matrix4x4_t tempmatrix = *matrix;
2966         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2967
2968         // if this light has been compiled before, free the associated data
2969         R_RTLight_Uncompile(rtlight);
2970
2971         // clear it completely to avoid any lingering data
2972         memset(rtlight, 0, sizeof(*rtlight));
2973
2974         // copy the properties
2975         rtlight->matrix_lighttoworld = tempmatrix;
2976         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2977         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2978         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2979         VectorCopy(color, rtlight->color);
2980         rtlight->cubemapname[0] = 0;
2981         if (cubemapname && cubemapname[0])
2982                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2983         rtlight->shadow = shadow;
2984         rtlight->corona = corona;
2985         rtlight->style = style;
2986         rtlight->isstatic = isstatic;
2987         rtlight->coronasizescale = coronasizescale;
2988         rtlight->ambientscale = ambientscale;
2989         rtlight->diffusescale = diffusescale;
2990         rtlight->specularscale = specularscale;
2991         rtlight->flags = flags;
2992
2993         // compute derived data
2994         //rtlight->cullradius = rtlight->radius;
2995         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2996         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2997         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2998         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2999         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3000         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3001         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3002 }
3003
3004 // compiles rtlight geometry
3005 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3006 void R_RTLight_Compile(rtlight_t *rtlight)
3007 {
3008         int i;
3009         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3010         int lighttris, shadowtris;
3011         entity_render_t *ent = r_refdef.scene.worldentity;
3012         dp_model_t *model = r_refdef.scene.worldmodel;
3013         unsigned char *data;
3014
3015         // compile the light
3016         rtlight->compiled = true;
3017         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3018         rtlight->static_numleafs = 0;
3019         rtlight->static_numleafpvsbytes = 0;
3020         rtlight->static_leaflist = NULL;
3021         rtlight->static_leafpvs = NULL;
3022         rtlight->static_numsurfaces = 0;
3023         rtlight->static_surfacelist = NULL;
3024         rtlight->static_shadowmap_receivers = 0x3F;
3025         rtlight->static_shadowmap_casters = 0x3F;
3026         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3027         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3028         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3029         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3030         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3031         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3032
3033         if (model && model->GetLightInfo)
3034         {
3035                 // this variable must be set for the CompileShadowMap code
3036                 r_shadow_compilingrtlight = rtlight;
3037                 R_FrameData_SetMark();
3038                 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL, rtlight->shadow == 0);
3039                 R_FrameData_ReturnToMark();
3040                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3041                 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3042                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3043                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3044                 rtlight->static_numsurfaces = numsurfaces;
3045                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3046                 rtlight->static_numleafs = numleafs;
3047                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3048                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3049                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3050                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3051                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3052                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3053                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3054                 if (rtlight->static_numsurfaces)
3055                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3056                 if (rtlight->static_numleafs)
3057                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3058                 if (rtlight->static_numleafpvsbytes)
3059                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3060                 if (rtlight->static_numshadowtrispvsbytes)
3061                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3062                 if (rtlight->static_numlighttrispvsbytes)
3063                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3064                 R_FrameData_SetMark();
3065                 if (model->CompileShadowMap && rtlight->shadow)
3066                         model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3067                 R_FrameData_ReturnToMark();
3068                 // now we're done compiling the rtlight
3069                 r_shadow_compilingrtlight = NULL;
3070         }
3071
3072
3073         // use smallest available cullradius - box radius or light radius
3074         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3075         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3076
3077         lighttris = 0;
3078         if (rtlight->static_numlighttrispvsbytes)
3079                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3080                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3081                                 lighttris++;
3082
3083         shadowtris = 0;
3084         if (rtlight->static_numshadowtrispvsbytes)
3085                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3086                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3087                                 shadowtris++;
3088
3089         if (developer_extra.integer)
3090                 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris);
3091 }
3092
3093 void R_RTLight_Uncompile(rtlight_t *rtlight)
3094 {
3095         if (rtlight->compiled)
3096         {
3097                 if (rtlight->static_meshchain_shadow_shadowmap)
3098                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3099                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3100                 // these allocations are grouped
3101                 if (rtlight->static_surfacelist)
3102                         Mem_Free(rtlight->static_surfacelist);
3103                 rtlight->static_numleafs = 0;
3104                 rtlight->static_numleafpvsbytes = 0;
3105                 rtlight->static_leaflist = NULL;
3106                 rtlight->static_leafpvs = NULL;
3107                 rtlight->static_numsurfaces = 0;
3108                 rtlight->static_surfacelist = NULL;
3109                 rtlight->static_numshadowtrispvsbytes = 0;
3110                 rtlight->static_shadowtrispvs = NULL;
3111                 rtlight->static_numlighttrispvsbytes = 0;
3112                 rtlight->static_lighttrispvs = NULL;
3113                 rtlight->compiled = false;
3114         }
3115 }
3116
3117 void R_Shadow_UncompileWorldLights(void)
3118 {
3119         size_t lightindex;
3120         dlight_t *light;
3121         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3122         for (lightindex = 0;lightindex < range;lightindex++)
3123         {
3124                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3125                 if (!light)
3126                         continue;
3127                 R_RTLight_Uncompile(&light->rtlight);
3128         }
3129 }
3130
3131 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3132 {
3133         int i, j;
3134         mplane_t plane;
3135         // reset the count of frustum planes
3136         // see rtlight->cached_frustumplanes definition for how much this array
3137         // can hold
3138         rtlight->cached_numfrustumplanes = 0;
3139
3140         if (r_trippy.integer)
3141                 return;
3142
3143         // haven't implemented a culling path for ortho rendering
3144         if (!r_refdef.view.useperspective)
3145         {
3146                 // check if the light is on screen and copy the 4 planes if it is
3147                 for (i = 0;i < 4;i++)
3148                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3149                                 break;
3150                 if (i == 4)
3151                         for (i = 0;i < 4;i++)
3152                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3153                 return;
3154         }
3155
3156 #if 1
3157         // generate a deformed frustum that includes the light origin, this is
3158         // used to cull shadow casting surfaces that can not possibly cast a
3159         // shadow onto the visible light-receiving surfaces, which can be a
3160         // performance gain
3161         //
3162         // if the light origin is onscreen the result will be 4 planes exactly
3163         // if the light origin is offscreen on only one axis the result will
3164         // be exactly 5 planes (split-side case)
3165         // if the light origin is offscreen on two axes the result will be
3166         // exactly 4 planes (stretched corner case)
3167         for (i = 0;i < 4;i++)
3168         {
3169                 // quickly reject standard frustum planes that put the light
3170                 // origin outside the frustum
3171                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3172                         continue;
3173                 // copy the plane
3174                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3175         }
3176         // if all the standard frustum planes were accepted, the light is onscreen
3177         // otherwise we need to generate some more planes below...
3178         if (rtlight->cached_numfrustumplanes < 4)
3179         {
3180                 // at least one of the stock frustum planes failed, so we need to
3181                 // create one or two custom planes to enclose the light origin
3182                 for (i = 0;i < 4;i++)
3183                 {
3184                         // create a plane using the view origin and light origin, and a
3185                         // single point from the frustum corner set
3186                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3187                         VectorNormalize(plane.normal);
3188                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3189                         // see if this plane is backwards and flip it if so
3190                         for (j = 0;j < 4;j++)
3191                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3192                                         break;
3193                         if (j < 4)
3194                         {
3195                                 VectorNegate(plane.normal, plane.normal);
3196                                 plane.dist *= -1;
3197                                 // flipped plane, test again to see if it is now valid
3198                                 for (j = 0;j < 4;j++)
3199                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3200                                                 break;
3201                                 // if the plane is still not valid, then it is dividing the
3202                                 // frustum and has to be rejected
3203                                 if (j < 4)
3204                                         continue;
3205                         }
3206                         // we have created a valid plane, compute extra info
3207                         PlaneClassify(&plane);
3208                         // copy the plane
3209                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3210 #if 1
3211                         // if we've found 5 frustum planes then we have constructed a
3212                         // proper split-side case and do not need to keep searching for
3213                         // planes to enclose the light origin
3214                         if (rtlight->cached_numfrustumplanes == 5)
3215                                 break;
3216 #endif
3217                 }
3218         }
3219 #endif
3220
3221 #if 0
3222         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3223         {
3224                 plane = rtlight->cached_frustumplanes[i];
3225                 Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
3226         }
3227 #endif
3228
3229 #if 0
3230         // now add the light-space box planes if the light box is rotated, as any
3231         // caster outside the oriented light box is irrelevant (even if it passed
3232         // the worldspace light box, which is axial)
3233         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3234         {
3235                 for (i = 0;i < 6;i++)
3236                 {
3237                         vec3_t v;
3238                         VectorClear(v);
3239                         v[i >> 1] = (i & 1) ? -1 : 1;
3240                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3241                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3242                         plane.dist = VectorNormalizeLength(plane.normal);
3243                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3244                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3245                 }
3246         }
3247 #endif
3248
3249 #if 0
3250         // add the world-space reduced box planes
3251         for (i = 0;i < 6;i++)
3252         {
3253                 VectorClear(plane.normal);
3254                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3255                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3256                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3257         }
3258 #endif
3259
3260 #if 0
3261         {
3262         int j, oldnum;
3263         vec3_t points[8];
3264         vec_t bestdist;
3265         // reduce all plane distances to tightly fit the rtlight cull box, which
3266         // is in worldspace
3267         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3268         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3269         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3270         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3271         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3272         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3273         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3274         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3275         oldnum = rtlight->cached_numfrustumplanes;
3276         rtlight->cached_numfrustumplanes = 0;
3277         for (j = 0;j < oldnum;j++)
3278         {
3279                 // find the nearest point on the box to this plane
3280                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3281                 for (i = 1;i < 8;i++)
3282                 {
3283                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3284                         if (bestdist > dist)
3285                                 bestdist = dist;
3286                 }
3287                 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rtlight->cached_frustumplanes[j].normal[0], rtlight->cached_frustumplanes[j].normal[1], rtlight->cached_frustumplanes[j].normal[2], rtlight->cached_frustumplanes[j].dist, bestdist);
3288                 // if the nearest point is near or behind the plane, we want this
3289                 // plane, otherwise the plane is useless as it won't cull anything
3290                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3291                 {
3292                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3293                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3294                 }
3295         }
3296         }
3297 #endif
3298 }
3299
3300 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3301 {
3302         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3303
3304         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3305         {
3306                 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3307                 if (mesh->sidetotals[r_shadow_shadowmapside])
3308                 {
3309                         CHECKGLERROR
3310                         GL_CullFace(GL_NONE);
3311                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3312                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3313                         R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3314                         CHECKGLERROR
3315                 }
3316         }
3317         else if (r_refdef.scene.worldentity->model)
3318                 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
3319
3320         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3321 }
3322
3323 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3324 {
3325         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3326         vec_t relativeshadowradius;
3327         RSurf_ActiveModelEntity(ent, false, false, false);
3328         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3329         // we need to re-init the shader for each entity because the matrix changed
3330         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3331         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3332         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3333         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3334         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3335         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3336         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3337         ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3338         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3339 }
3340
3341 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3342 {
3343         // set up properties for rendering light onto this entity
3344         RSurf_ActiveModelEntity(ent, true, true, false);
3345         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3346         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3347         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3348         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3349 }
3350
3351 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3352 {
3353         if (!r_refdef.scene.worldmodel->DrawLight)
3354                 return;
3355
3356         // set up properties for rendering light onto this entity
3357         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3358         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3359         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3360         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3361         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3362
3363         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3364
3365         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3366 }
3367
3368 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3369 {
3370         dp_model_t *model = ent->model;
3371         if (!model->DrawLight)
3372                 return;
3373
3374         R_Shadow_SetupEntityLight(ent);
3375
3376         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3377
3378         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3379 }
3380
3381 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3382 {
3383         int i;
3384         float f;
3385         int numleafs, numsurfaces;
3386         int *leaflist, *surfacelist;
3387         unsigned char *leafpvs;
3388         unsigned char *shadowtrispvs;
3389         unsigned char *lighttrispvs;
3390         //unsigned char *surfacesides;
3391         int numlightentities;
3392         int numlightentities_noselfshadow;
3393         int numshadowentities;
3394         int numshadowentities_noselfshadow;
3395         // FIXME: bounds check lightentities and shadowentities, etc.
3396         static entity_render_t *lightentities[MAX_EDICTS];
3397         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3398         static entity_render_t *shadowentities[MAX_EDICTS];
3399         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3400         qboolean nolight;
3401         qboolean castshadows;
3402
3403         rtlight->draw = false;
3404         rtlight->cached_numlightentities = 0;
3405         rtlight->cached_numlightentities_noselfshadow = 0;
3406         rtlight->cached_numshadowentities = 0;
3407         rtlight->cached_numshadowentities_noselfshadow = 0;
3408         rtlight->cached_numsurfaces = 0;
3409         rtlight->cached_lightentities = NULL;
3410         rtlight->cached_lightentities_noselfshadow = NULL;
3411         rtlight->cached_shadowentities = NULL;
3412         rtlight->cached_shadowentities_noselfshadow = NULL;
3413         rtlight->cached_shadowtrispvs = NULL;
3414         rtlight->cached_lighttrispvs = NULL;
3415         rtlight->cached_surfacelist = NULL;
3416         rtlight->shadowmapsidesize = 0;
3417
3418         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3419         // skip lights that are basically invisible (color 0 0 0)
3420         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3421
3422         // loading is done before visibility checks because loading should happen
3423         // all at once at the start of a level, not when it stalls gameplay.
3424         // (especially important to benchmarks)
3425         // compile light
3426         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3427         {
3428                 if (rtlight->compiled)
3429                         R_RTLight_Uncompile(rtlight);
3430                 R_RTLight_Compile(rtlight);
3431         }
3432
3433         // load cubemap
3434         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3435
3436         // look up the light style value at this time
3437         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3438         VectorScale(rtlight->color, f, rtlight->currentcolor);
3439         /*
3440         if (rtlight->selected)
3441         {
3442                 f = 2 + sin(realtime * M_PI * 4.0);
3443                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3444         }
3445         */
3446
3447         // skip if lightstyle is currently off
3448         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3449                 return;
3450
3451         // skip processing on corona-only lights
3452         if (nolight)
3453                 return;
3454
3455         // skip if the light box is not touching any visible leafs
3456         if (r_shadow_culllights_pvs.integer
3457                 && r_refdef.scene.worldmodel
3458                 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3459                 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3460                 return;
3461
3462         // skip if the light box is not visible to traceline
3463         if (r_shadow_culllights_trace.integer)
3464         {
3465                 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
3466                         rtlight->trace_timer = realtime;
3467                 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3468                         return;
3469         }
3470
3471         // skip if the light box is off screen
3472         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3473                 return;
3474
3475         // in the typical case this will be quickly replaced by GetLightInfo
3476         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3477         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3478
3479         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3480
3481         // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw
3482         if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3483                 return;
3484
3485         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3486         {
3487                 // compiled light, world available and can receive realtime lighting
3488                 // retrieve leaf information
3489                 numleafs = rtlight->static_numleafs;
3490                 leaflist = rtlight->static_leaflist;
3491                 leafpvs = rtlight->static_leafpvs;
3492                 numsurfaces = rtlight->static_numsurfaces;
3493                 surfacelist = rtlight->static_surfacelist;
3494                 //surfacesides = NULL;
3495                 shadowtrispvs = rtlight->static_shadowtrispvs;
3496                 lighttrispvs = rtlight->static_lighttrispvs;
3497         }
3498         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3499         {
3500                 // dynamic light, world available and can receive realtime lighting
3501                 // calculate lit surfaces and leafs
3502                 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes, rtlight->shadow == 0);
3503                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3504                 leaflist = r_shadow_buffer_leaflist;
3505                 leafpvs = r_shadow_buffer_leafpvs;
3506                 surfacelist = r_shadow_buffer_surfacelist;
3507                 //surfacesides = r_shadow_buffer_surfacesides;
3508                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3509                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3510                 // if the reduced leaf bounds are offscreen, skip it
3511                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3512                         return;
3513         }
3514         else
3515         {
3516                 // no world
3517                 numleafs = 0;
3518                 leaflist = NULL;
3519                 leafpvs = NULL;
3520                 numsurfaces = 0;
3521                 surfacelist = NULL;
3522                 //surfacesides = NULL;
3523                 shadowtrispvs = NULL;
3524                 lighttrispvs = NULL;
3525         }
3526         // check if light is illuminating any visible leafs
3527         if (numleafs)
3528         {
3529                 for (i = 0; i < numleafs; i++)
3530                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3531                                 break;
3532                 if (i == numleafs)
3533                         return;
3534         }
3535
3536         // make a list of lit entities and shadow casting entities
3537         numlightentities = 0;
3538         numlightentities_noselfshadow = 0;
3539         numshadowentities = 0;
3540         numshadowentities_noselfshadow = 0;
3541
3542         // add dynamic entities that are lit by the light
3543         for (i = 0; i < r_refdef.scene.numentities; i++)
3544         {
3545                 dp_model_t *model;
3546                 entity_render_t *ent = r_refdef.scene.entities[i];
3547                 vec3_t org;
3548                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3549                         continue;
3550                 // skip the object entirely if it is not within the valid
3551                 // shadow-casting region (which includes the lit region)
3552                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3553                         continue;
3554                 if (!(model = ent->model))
3555                         continue;
3556                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3557                 {
3558                         // this entity wants to receive light, is visible, and is
3559                         // inside the light box
3560                         // TODO: check if the surfaces in the model can receive light
3561                         // so now check if it's in a leaf seen by the light
3562                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3563                                 continue;
3564                         if (ent->flags & RENDER_NOSELFSHADOW)
3565                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3566                         else
3567                                 lightentities[numlightentities++] = ent;
3568                         // since it is lit, it probably also casts a shadow...
3569                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3570                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3571                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3572                         {
3573                                 // note: exterior models without the RENDER_NOSELFSHADOW
3574                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3575                                 // are lit normally, this means that they are
3576                                 // self-shadowing but do not shadow other
3577                                 // RENDER_NOSELFSHADOW entities such as the gun
3578                                 // (very weird, but keeps the player shadow off the gun)
3579                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3580                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3581                                 else
3582                                         shadowentities[numshadowentities++] = ent;
3583                         }
3584                 }
3585                 else if (ent->flags & RENDER_SHADOW)
3586                 {
3587                         // this entity is not receiving light, but may still need to
3588                         // cast a shadow...
3589                         // TODO: check if the surfaces in the model can cast shadow
3590                         // now check if it is in a leaf seen by the light
3591                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3592                                 continue;
3593                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3594                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3595                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3596                         {
3597                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3598                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3599                                 else
3600                                         shadowentities[numshadowentities++] = ent;
3601                         }
3602                 }
3603         }
3604
3605         // return if there's nothing at all to light
3606         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3607                 return;
3608
3609         // count this light in the r_speeds
3610         r_refdef.stats[r_stat_lights]++;
3611
3612         // flag it as worth drawing later
3613         rtlight->draw = true;
3614
3615         // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3616         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3617         if (!castshadows)
3618                 numshadowentities = numshadowentities_noselfshadow = 0;
3619         rtlight->castshadows = castshadows;
3620
3621         // cache all the animated entities that cast a shadow but are not visible
3622         for (i = 0; i < numshadowentities; i++)
3623                 R_AnimCache_GetEntity(shadowentities[i], false, false);
3624         for (i = 0; i < numshadowentities_noselfshadow; i++)
3625                 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3626
3627         // we can convert noselfshadow to regular if there are no receivers of that type (or we're using r_shadow_deferred which doesn't support noselfshadow anyway)
3628         if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3629         {
3630                 for (i = 0; i < numshadowentities_noselfshadow; i++)
3631                         shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3632                 numshadowentities_noselfshadow = 0;
3633         }
3634
3635         // we can convert noselfshadow to regular if there are no casters of that type
3636         if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3637         {
3638                 for (i = 0; i < numlightentities_noselfshadow; i++)
3639                         lightentities[numlightentities++] = lightentities_noselfshadow[i];
3640                 numlightentities_noselfshadow = 0;
3641         }
3642
3643         // allocate some temporary memory for rendering this light later in the frame
3644         // reusable buffers need to be copied, static data can be used as-is
3645         rtlight->cached_numlightentities               = numlightentities;
3646         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
3647         rtlight->cached_numshadowentities              = numshadowentities;
3648         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3649         rtlight->cached_numsurfaces                    = numsurfaces;
3650         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3651         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3652         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3653         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3654         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3655         {
3656                 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3657                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3658                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3659                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3660                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3661         }
3662         else
3663         {
3664                 // compiled light data
3665                 rtlight->cached_shadowtrispvs = shadowtrispvs;
3666                 rtlight->cached_lighttrispvs = lighttrispvs;
3667                 rtlight->cached_surfacelist = surfacelist;
3668         }
3669
3670         if (R_Shadow_ShadowMappingEnabled())
3671         {
3672                 // figure out the shadowmapping parameters for this light
3673                 vec3_t nearestpoint;
3674                 vec_t distance;
3675                 int lodlinear;
3676                 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3677                 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3678                 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3679                 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3680                 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3681                 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3682                 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3683                 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3684                 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3685         }
3686 }
3687
3688 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3689 {
3690         int i;
3691         int numsurfaces;
3692         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3693         int numlightentities;
3694         int numlightentities_noselfshadow;
3695         int numshadowentities;
3696         int numshadowentities_noselfshadow;
3697         entity_render_t **lightentities;
3698         entity_render_t **lightentities_noselfshadow;
3699         entity_render_t **shadowentities;
3700         entity_render_t **shadowentities_noselfshadow;
3701         int *surfacelist;
3702         static unsigned char entitysides[MAX_EDICTS];
3703         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3704         float borderbias;
3705         int side;
3706         int size;
3707         int castermask;
3708         int receivermask;
3709         matrix4x4_t radiustolight;
3710
3711         // check if we cached this light this frame (meaning it is worth drawing)
3712         if (!rtlight->draw || !rtlight->castshadows)
3713                 return;
3714
3715         // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3716         if (rtlight->shadowmapatlassidesize == 0)
3717         {
3718                 rtlight->castshadows = false;
3719                 return;
3720         }
3721
3722         // set up a scissor rectangle for this light
3723         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3724                 return;
3725
3726         // don't let sound skip if going slow
3727         if (r_refdef.scene.extraupdate)
3728                 S_ExtraUpdate();
3729
3730         numlightentities = rtlight->cached_numlightentities;
3731         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3732         numshadowentities = rtlight->cached_numshadowentities;
3733         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3734         numsurfaces = rtlight->cached_numsurfaces;
3735         lightentities = rtlight->cached_lightentities;
3736         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3737         shadowentities = rtlight->cached_shadowentities;
3738         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3739         shadowtrispvs = rtlight->cached_shadowtrispvs;
3740         lighttrispvs = rtlight->cached_lighttrispvs;
3741         surfacelist = rtlight->cached_surfacelist;
3742
3743         // make this the active rtlight for rendering purposes
3744         R_Shadow_RenderMode_ActiveLight(rtlight);
3745
3746         radiustolight = rtlight->matrix_worldtolight;
3747         Matrix4x4_Abs(&radiustolight);
3748
3749         size = rtlight->shadowmapatlassidesize;
3750         borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3751
3752         surfacesides = NULL;
3753         castermask = 0;
3754         receivermask = 0;
3755         if (numsurfaces)
3756         {
3757                 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3758                 {
3759                         castermask = rtlight->static_shadowmap_casters;
3760                         receivermask = rtlight->static_shadowmap_receivers;
3761                 }
3762                 else
3763                 {
3764                         surfacesides = r_shadow_buffer_surfacesides;
3765                         for (i = 0; i < numsurfaces; i++)
3766                         {
3767                                 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3768                                 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3769                                 castermask |= surfacesides[i];
3770                                 receivermask |= surfacesides[i];
3771                         }
3772                 }
3773         }
3774
3775         for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3776                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3777         for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3778                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3779
3780         receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3781
3782         if (receivermask)
3783         {
3784                 for (i = 0; i < numshadowentities; i++)
3785                         castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3786                 for (i = 0; i < numshadowentities_noselfshadow; i++)
3787                         castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3788         }
3789
3790         // there is no need to render shadows for sides that have no receivers...
3791         castermask &= receivermask;
3792
3793         //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3794
3795         // render shadow casters into shadowmaps for this light
3796         for (side = 0; side < 6; side++)
3797         {
3798                 int bit = 1 << side;
3799                 if (castermask & bit)
3800                 {
3801                         R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3802                         if (numsurfaces)
3803                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3804                         for (i = 0; i < numshadowentities; i++)
3805                                 if (entitysides[i] & bit)
3806                                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3807                         for (i = 0; i < numshadowentities_noselfshadow; i++)
3808                                 if (entitysides_noselfshadow[i] & bit)
3809                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3810                 }
3811         }
3812         // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3813         if (numshadowentities_noselfshadow)
3814         {
3815                 for (side = 0; side < 6; side++)
3816                 {
3817                         int bit = 1 << side;
3818                         if (castermask & bit)
3819                         {
3820                                 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3821                                 if (numsurfaces)
3822                                         R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3823                                 for (i = 0; i < numshadowentities; i++)
3824                                         if (entitysides[i] & bit)
3825                                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3826                         }
3827                 }
3828         }
3829 }
3830
3831 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3832 {
3833         int i;
3834         int numsurfaces;
3835         unsigned char *shadowtrispvs, *lighttrispvs;
3836         int numlightentities;
3837         int numlightentities_noselfshadow;
3838         int numshadowentities;
3839         int numshadowentities_noselfshadow;
3840         entity_render_t **lightentities;
3841         entity_render_t **lightentities_noselfshadow;
3842         entity_render_t **shadowentities;
3843         entity_render_t **shadowentities_noselfshadow;
3844         int *surfacelist;
3845         qboolean castshadows;
3846
3847         // check if we cached this light this frame (meaning it is worth drawing)
3848         if (!rtlight->draw)
3849                 return;
3850
3851         // set up a scissor rectangle for this light
3852         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3853                 return;
3854
3855         // don't let sound skip if going slow
3856         if (r_refdef.scene.extraupdate)
3857                 S_ExtraUpdate();
3858
3859         numlightentities = rtlight->cached_numlightentities;
3860         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3861         numshadowentities = rtlight->cached_numshadowentities;
3862         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3863         numsurfaces = rtlight->cached_numsurfaces;
3864         lightentities = rtlight->cached_lightentities;
3865         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3866         shadowentities = rtlight->cached_shadowentities;
3867         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3868         shadowtrispvs = rtlight->cached_shadowtrispvs;
3869         lighttrispvs = rtlight->cached_lighttrispvs;
3870         surfacelist = rtlight->cached_surfacelist;
3871         castshadows = rtlight->castshadows;
3872
3873         // make this the active rtlight for rendering purposes
3874         R_Shadow_RenderMode_ActiveLight(rtlight);
3875
3876         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3877         {
3878                 // optionally draw the illuminated areas
3879                 // for performance analysis by level designers
3880                 R_Shadow_RenderMode_VisibleLighting(false);
3881                 if (numsurfaces)
3882                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3883                 for (i = 0;i < numlightentities;i++)
3884                         R_Shadow_DrawEntityLight(lightentities[i]);
3885                 for (i = 0;i < numlightentities_noselfshadow;i++)
3886                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3887         }
3888
3889         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3890         {
3891                 float borderbias;
3892                 int size;
3893                 float shadowmapoffsetnoselfshadow = 0;
3894                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3895                 Matrix4x4_Abs(&radiustolight);
3896
3897                 size = rtlight->shadowmapatlassidesize;
3898                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3899
3900                 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3901
3902                 if (rtlight->cached_numshadowentities_noselfshadow)
3903                         shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3904
3905                 // render lighting using the depth texture as shadowmap
3906                 // draw lighting in the unmasked areas
3907                 if (numsurfaces + numlightentities)
3908                 {
3909                         R_Shadow_RenderMode_Lighting(false, true, false);
3910                         // draw lighting in the unmasked areas
3911                         if (numsurfaces)
3912                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3913                         for (i = 0; i < numlightentities; i++)
3914                                 R_Shadow_DrawEntityLight(lightentities[i]);
3915                 }
3916                 // offset to the noselfshadow part of the atlas and draw those too
3917                 if (numlightentities_noselfshadow)
3918                 {
3919                         R_Shadow_RenderMode_Lighting(false, true, true);
3920                         for (i = 0; i < numlightentities_noselfshadow; i++)
3921                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3922                 }
3923
3924                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3925                 if (r_shadow_usingdeferredprepass)
3926                         R_Shadow_RenderMode_DrawDeferredLight(true);
3927         }
3928         else
3929         {
3930                 // draw lighting in the unmasked areas
3931                 R_Shadow_RenderMode_Lighting(false, false, false);
3932                 if (numsurfaces)
3933                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3934                 for (i = 0;i < numlightentities;i++)
3935                         R_Shadow_DrawEntityLight(lightentities[i]);
3936                 for (i = 0;i < numlightentities_noselfshadow;i++)
3937                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3938
3939                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3940                 if (r_shadow_usingdeferredprepass)
3941                         R_Shadow_RenderMode_DrawDeferredLight(false);
3942         }
3943 }
3944
3945 static void R_Shadow_FreeDeferred(void)
3946 {
3947         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3948         r_shadow_prepassgeometryfbo = 0;
3949
3950         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3951         r_shadow_prepasslightingdiffusespecularfbo = 0;
3952
3953         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3954         r_shadow_prepasslightingdiffusefbo = 0;
3955
3956         if (r_shadow_prepassgeometrydepthbuffer)
3957                 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3958         r_shadow_prepassgeometrydepthbuffer = NULL;
3959
3960         if (r_shadow_prepassgeometrynormalmaptexture)
3961                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3962         r_shadow_prepassgeometrynormalmaptexture = NULL;
3963
3964         if (r_shadow_prepasslightingdiffusetexture)
3965                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3966         r_shadow_prepasslightingdiffusetexture = NULL;
3967
3968         if (r_shadow_prepasslightingspeculartexture)
3969                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3970         r_shadow_prepasslightingspeculartexture = NULL;
3971 }
3972
3973 void R_Shadow_DrawPrepass(void)
3974 {
3975         int i;
3976         int lnum;
3977         entity_render_t *ent;
3978         float clearcolor[4];
3979
3980         R_Mesh_ResetTextureState();
3981         GL_DepthMask(true);
3982         GL_ColorMask(1,1,1,1);
3983         GL_BlendFunc(GL_ONE, GL_ZERO);
3984         GL_Color(1,1,1,1);
3985         GL_DepthTest(true);
3986         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3987         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3988         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3989         if (r_timereport_active)
3990                 R_TimeReport("prepasscleargeom");
3991
3992         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3993                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3994         if (r_timereport_active)
3995                 R_TimeReport("prepassworld");
3996
3997         for (i = 0;i < r_refdef.scene.numentities;i++)
3998         {
3999                 if (!r_refdef.viewcache.entityvisible[i])
4000                         continue;
4001                 ent = r_refdef.scene.entities[i];
4002                 if (ent->model && ent->model->DrawPrepass != NULL)
4003                         ent->model->DrawPrepass(ent);
4004         }
4005
4006         if (r_timereport_active)
4007                 R_TimeReport("prepassmodels");
4008
4009         GL_DepthMask(false);
4010         GL_ColorMask(1,1,1,1);
4011         GL_Color(1,1,1,1);
4012         GL_DepthTest(true);
4013         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4014         Vector4Set(clearcolor, 0, 0, 0, 0);
4015         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4016         if (r_timereport_active)
4017                 R_TimeReport("prepassclearlit");
4018
4019         R_Shadow_RenderMode_Begin();
4020
4021         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4022                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4023
4024         R_Shadow_RenderMode_End();
4025
4026         if (r_timereport_active)
4027                 R_TimeReport("prepasslights");
4028 }
4029
4030 #define MAX_SCENELIGHTS 65536
4031 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4032 {
4033         if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4034         {
4035                 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4036                         return false;
4037                 r_shadow_scenemaxlights *= 2;
4038                 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4039                 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4040         }
4041         r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4042         return true;
4043 }
4044
4045 void R_Shadow_DrawLightSprites(void);
4046 void R_Shadow_PrepareLights(void)
4047 {
4048         int flag;
4049         int lnum;
4050         size_t lightindex;
4051         dlight_t *light;
4052         size_t range;
4053         float f;
4054
4055         int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4056         int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4057         int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4058
4059         if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4060                 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4061                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4062                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4063                 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4064                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4065                 r_shadow_shadowmapborder != shadowmapborder ||
4066                 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4067                 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4068                 R_Shadow_FreeShadowMaps();
4069
4070         r_shadow_usingshadowmaportho = false;
4071
4072         switch (vid.renderpath)
4073         {
4074         case RENDERPATH_GL32:
4075 #ifndef USE_GLES2
4076                 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4077                 {
4078                         r_shadow_usingdeferredprepass = false;
4079                         if (r_shadow_prepass_width)
4080                                 R_Shadow_FreeDeferred();
4081                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4082                         break;
4083                 }
4084
4085                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4086                 {
4087                         R_Shadow_FreeDeferred();
4088
4089                         r_shadow_usingdeferredprepass = true;
4090                         r_shadow_prepass_width = vid.width;
4091                         r_shadow_prepass_height = vid.height;
4092                         r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4093                         r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4094                         r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4095                         r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4096
4097                         // set up the geometry pass fbo (depth + normalmap)
4098                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4099                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4100                         // render depth into a renderbuffer and other important properties into the normalmap texture
4101
4102                         // set up the lighting pass fbo (diffuse + specular)
4103                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4104                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4105                         // render diffuse into one texture and specular into another,
4106                         // with depth and normalmap bound as textures,
4107                         // with depth bound as attachment as well
4108
4109                         // set up the lighting pass fbo (diffuse)
4110                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4111                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4112                         // render diffuse into one texture,
4113                         // with depth and normalmap bound as textures,
4114                         // with depth bound as attachment as well
4115                 }
4116 #endif
4117                 break;
4118         case RENDERPATH_GLES2:
4119                 r_shadow_usingdeferredprepass = false;
4120                 break;
4121         }
4122
4123         R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
4124
4125         r_shadow_scenenumlights = 0;
4126         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4127         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4128         for (lightindex = 0; lightindex < range; lightindex++)
4129         {
4130                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4131                 if (light && (light->flags & flag))
4132                 {
4133                         R_Shadow_PrepareLight(&light->rtlight);
4134                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4135                 }
4136         }
4137         if (r_refdef.scene.rtdlight)
4138         {
4139                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4140                 {
4141                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4142                         R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4143                 }
4144         }
4145         else if (gl_flashblend.integer)
4146         {
4147                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4148                 {
4149                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4150                         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4151                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4152                 }
4153         }
4154
4155         // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4156         if (r_shadow_debuglight.integer >= 0)
4157         {
4158                 r_shadow_scenenumlights = 0;
4159                 lightindex = r_shadow_debuglight.integer;
4160                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4161                 if (light)
4162                 {
4163                         R_Shadow_PrepareLight(&light->rtlight);
4164                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4165                 }
4166         }
4167
4168         // if we're doing shadowmaps we need to prepare the atlas layout now
4169         if (R_Shadow_ShadowMappingEnabled())
4170         {
4171                 int lod;
4172
4173                 // allocate shadowmaps in the atlas now
4174                 // we may have to make multiple attempts to fit the shadowmaps in the limited space of the atlas, this will appear as lod popping of all shadowmaps whenever it changes, but at least we can still cast shadows from all lights...
4175                 for (lod = 0; lod < 16; lod++)
4176                 {
4177                         int packing_success = 0;
4178                         int packing_failure = 0;
4179                         Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4180                         // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4181                         if (r_shadow_shadowmapatlas_modelshadows_size)
4182                                 Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, &r_shadow_shadowmapatlas_modelshadows_x, &r_shadow_shadowmapatlas_modelshadows_y);
4183                         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4184                         {
4185                                 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4186                                 int size = rtlight->shadowmapsidesize >> lod;
4187                                 int width, height;
4188                                 if (!rtlight->castshadows)
4189                                         continue;
4190                                 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4191                                 width = size * 2;
4192                                 height = size * 3;
4193                                 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4194                                 if (rtlight->cached_numshadowentities_noselfshadow)
4195                                         width *= 2;
4196                                 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4197                                 {
4198                                         rtlight->shadowmapatlassidesize = size;
4199                                         packing_success++;
4200                                 }
4201                                 else
4202                                 {
4203                                         // note down that we failed to pack this one, it will have to disable shadows
4204                                         rtlight->shadowmapatlassidesize = 0;
4205                                         packing_failure++;
4206                                 }
4207                         }
4208                         // generally everything fits and we stop here on the first iteration
4209                         if (packing_failure == 0)
4210                                 break;
4211                 }
4212         }
4213
4214         if (r_editlights.integer)
4215                 R_Shadow_DrawLightSprites();
4216 }
4217
4218 void R_Shadow_DrawShadowMaps(void)
4219 {
4220         R_Shadow_RenderMode_Begin();
4221         R_Shadow_RenderMode_ActiveLight(NULL);
4222
4223         // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4224         R_Shadow_ClearShadowMapTexture();
4225
4226         // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4227         if (r_shadow_shadowmapatlas_modelshadows_size)
4228         {
4229                 R_Shadow_DrawModelShadowMaps();
4230                 // don't let sound skip if going slow
4231                 if (r_refdef.scene.extraupdate)
4232                         S_ExtraUpdate();
4233         }
4234
4235         if (R_Shadow_ShadowMappingEnabled())
4236         {
4237                 int lnum;
4238                 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4239                         R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4240         }
4241
4242         R_Shadow_RenderMode_End();
4243 }
4244
4245 void R_Shadow_DrawLights(void)
4246 {
4247         int lnum;
4248
4249         R_Shadow_RenderMode_Begin();
4250
4251         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4252                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4253
4254         R_Shadow_RenderMode_End();
4255 }
4256
4257 #define MAX_MODELSHADOWS 1024
4258 static int r_shadow_nummodelshadows;
4259 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4260
4261 void R_Shadow_PrepareModelShadows(void)
4262 {
4263         int i;
4264         float scale, size, radius, dot1, dot2;
4265         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4266         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4267         entity_render_t *ent;
4268
4269         r_shadow_nummodelshadows = 0;
4270         r_shadow_shadowmapatlas_modelshadows_size = 0;
4271
4272         if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4273                 return;
4274
4275         size = r_shadow_shadowmaptexturesize / 4;
4276         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4277         radius = 0.5f * size / scale;
4278
4279         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4280         VectorCopy(prvmshadowdir, shadowdir);
4281         VectorNormalize(shadowdir);
4282         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4283         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4284         if (fabs(dot1) <= fabs(dot2))
4285                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4286         else
4287                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4288         VectorNormalize(shadowforward);
4289         CrossProduct(shadowdir, shadowforward, shadowright);
4290         Math_atov(r_shadows_focus.string, prvmshadowfocus);
4291         VectorCopy(prvmshadowfocus, shadowfocus);
4292         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4293         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4294         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4295         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4296         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4297                 dot1 = 1;
4298         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4299
4300         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4301         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4302         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4303         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4304         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4305         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4306
4307         for (i = 0; i < r_refdef.scene.numentities; i++)
4308         {
4309                 ent = r_refdef.scene.entities[i];
4310                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4311                         continue;
4312                 // cast shadows from anything of the map (submodels are optional)
4313                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4314                 {
4315                         if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4316                                 break;
4317                         r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4318                         R_AnimCache_GetEntity(ent, false, false);
4319                 }
4320         }
4321
4322         if (r_shadow_nummodelshadows)
4323         {
4324                 r_shadow_shadowmapatlas_modelshadows_x = 0;
4325                 r_shadow_shadowmapatlas_modelshadows_y = 0;
4326                 r_shadow_shadowmapatlas_modelshadows_size = size;
4327         }
4328 }
4329
4330 static void R_Shadow_DrawModelShadowMaps(void)
4331 {
4332         int i;
4333         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4334         entity_render_t *ent;
4335         vec3_t relativelightorigin;
4336         vec3_t relativelightdirection, relativeforward, relativeright;
4337         vec3_t relativeshadowmins, relativeshadowmaxs;
4338         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4339         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4340         float m[12];
4341         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4342         r_viewport_t viewport;
4343
4344         size = r_shadow_shadowmapatlas_modelshadows_size;
4345         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4346         radius = 0.5f / scale;
4347         nearclip = -r_shadows_throwdistance.value;
4348         farclip = r_shadows_throwdistance.value;
4349         bias = (r_shadows_shadowmapbias.value < 0) ? r_shadow_shadowmapping_bias.value : r_shadows_shadowmapbias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4350
4351         // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4352         r_shadow_modelshadowmap_parameters[0] = size;
4353         r_shadow_modelshadowmap_parameters[1] = size;
4354         r_shadow_modelshadowmap_parameters[2] = 1.0;
4355         r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4356         r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4357         r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4358         r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4359         r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4360         r_shadow_usingshadowmaportho = true;
4361
4362         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4363         VectorCopy(prvmshadowdir, shadowdir);
4364         VectorNormalize(shadowdir);
4365         Math_atov(r_shadows_focus.string, prvmshadowfocus);
4366         VectorCopy(prvmshadowfocus, shadowfocus);
4367         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4368         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4369         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4370         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4371         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4372         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4373         if (fabs(dot1) <= fabs(dot2))
4374                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4375         else
4376                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4377         VectorNormalize(shadowforward);
4378         VectorM(scale, shadowforward, &m[0]);
4379         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4380                 dot1 = 1;
4381         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4382         CrossProduct(shadowdir, shadowforward, shadowright);
4383         VectorM(scale, shadowright, &m[4]);
4384         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4385         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4386         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4387         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4388         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4389         R_Viewport_InitOrtho(&viewport, &cameramatrix, r_shadow_shadowmapatlas_modelshadows_x, r_shadow_shadowmapatlas_modelshadows_y, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, 0, 0, 1, 1, 0, -1, NULL);
4390         R_SetViewport(&viewport);
4391
4392         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4393
4394         // render into a slightly restricted region so that the borders of the
4395         // shadowmap area fade away, rather than streaking across everything
4396         // outside the usable area
4397         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4398
4399         for (i = 0;i < r_shadow_nummodelshadows;i++)
4400         {
4401                 ent = r_shadow_modelshadows[i];
4402                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4403                 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4404                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4405                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4406                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4407                 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4408                 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4409                 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4410                 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4411                 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4412                 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4413                 RSurf_ActiveModelEntity(ent, false, false, false);
4414                 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4415                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4416         }
4417
4418 #if 0
4419         if (r_test.integer)
4420         {
4421                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4422                 CHECKGLERROR
4423                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4424                 CHECKGLERROR
4425                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4426                 Cvar_SetValueQuick(&r_test, 0);
4427                 Z_Free(rawpixels);
4428         }
4429 #endif
4430
4431         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4432         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4433         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4434         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4435         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4436         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4437 }
4438
4439 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4440 {
4441         float zdist;
4442         vec3_t centerorigin;
4443 #ifndef USE_GLES2
4444         float vertex3f[12];
4445 #endif
4446         // if it's too close, skip it
4447         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4448                 return;
4449         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4450         if (zdist < 32)
4451                 return;
4452         if (usequery && r_numqueries + 2 <= r_maxqueries)
4453         {
4454                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4455                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4456                 // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights
4457                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4458
4459                 switch(vid.renderpath)
4460                 {
4461                 case RENDERPATH_GL32:
4462                 case RENDERPATH_GLES2:
4463 #ifndef USE_GLES2
4464                         CHECKGLERROR
4465                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4466                         qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4467                         GL_DepthFunc(GL_ALWAYS);
4468                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4469                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4470                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4471                         qglEndQuery(GL_SAMPLES_PASSED);
4472                         GL_DepthFunc(GL_LEQUAL);
4473                         qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4474                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4475                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4476                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4477                         qglEndQuery(GL_SAMPLES_PASSED);
4478                         CHECKGLERROR
4479 #endif
4480                         break;
4481                 }
4482         }
4483         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4484 }
4485
4486 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4487
4488 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4489 {
4490         vec3_t color;
4491         unsigned int occlude = 0;
4492
4493         // now we have to check the query result
4494         if (rtlight->corona_queryindex_visiblepixels)
4495         {
4496                 switch(vid.renderpath)
4497                 {
4498                 case RENDERPATH_GL32:
4499                 case RENDERPATH_GLES2:
4500 #ifndef USE_GLES2
4501                         // store the pixel counts into a uniform buffer for the shader to
4502                         // use - we'll never know the results on the cpu without
4503                         // synchronizing and we don't want that
4504 #define BUFFER_OFFSET(i)    ((GLint *)((unsigned char*)NULL + (i)))
4505                         if (!r_shadow_occlusion_buf) {
4506                                 qglGenBuffers(1, &r_shadow_occlusion_buf);
4507                                 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4508                                 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4509                         } else {
4510                                 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4511                         }
4512                         qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4513                         qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4514                         qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4515                         occlude = MATERIALFLAG_OCCLUDE;
4516                         cscale *= rtlight->corona_visibility;
4517                         CHECKGLERROR
4518                         break;
4519 #else
4520                         return;
4521 #endif
4522                 }
4523         }
4524         else
4525         {
4526                 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4527                         return;
4528         }
4529         VectorScale(rtlight->currentcolor, cscale, color);
4530         if (VectorLength(color) > (1.0f / 256.0f))
4531         {
4532                 float vertex3f[12];
4533                 qboolean negated = (color[0] + color[1] + color[2] < 0);
4534                 if(negated)
4535                 {
4536                         VectorNegate(color, color);
4537                         GL_BlendEquationSubtract(true);
4538                 }
4539                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4540                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4541                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4542                 if(negated)
4543                         GL_BlendEquationSubtract(false);
4544         }
4545 }
4546
4547 void R_Shadow_DrawCoronas(void)
4548 {
4549         int i, flag;
4550         qboolean usequery = false;
4551         size_t lightindex;
4552         dlight_t *light;
4553         rtlight_t *rtlight;
4554         size_t range;
4555         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4556                 return;
4557         if (r_fb.water.renderingscene)
4558                 return;
4559         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4560         R_EntityMatrix(&identitymatrix);
4561
4562         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4563
4564         // check occlusion of coronas, using occlusion queries or raytraces
4565         r_numqueries = 0;
4566         switch (vid.renderpath)
4567         {
4568         case RENDERPATH_GL32:
4569         case RENDERPATH_GLES2:
4570                 usequery = r_coronas_occlusionquery.integer;
4571 #ifndef USE_GLES2
4572                 if (usequery)
4573                 {
4574                         GL_ColorMask(0,0,0,0);
4575                         if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4576                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4577                         {
4578                                 i = r_maxqueries;
4579                                 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4580                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4581                                 CHECKGLERROR
4582                                 qglGenQueries(r_maxqueries - i, r_queries + i);
4583                                 CHECKGLERROR
4584                         }
4585                         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4586                         GL_BlendFunc(GL_ONE, GL_ZERO);
4587                         GL_CullFace(GL_NONE);
4588                         GL_DepthMask(false);
4589                         GL_DepthRange(0, 1);
4590                         GL_PolygonOffset(0, 0);
4591                         GL_DepthTest(true);
4592                         R_Mesh_ResetTextureState();
4593                         R_SetupShader_Generic_NoTexture(false, false);
4594                 }
4595 #endif
4596                 break;
4597         }
4598         for (lightindex = 0;lightindex < range;lightindex++)
4599         {
4600                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4601                 if (!light)
4602                         continue;
4603                 rtlight = &light->rtlight;
4604                 rtlight->corona_visibility = 0;
4605                 rtlight->corona_queryindex_visiblepixels = 0;
4606                 rtlight->corona_queryindex_allpixels = 0;
4607                 if (!(rtlight->flags & flag))
4608                         continue;
4609                 if (rtlight->corona <= 0)
4610                         continue;
4611                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4612                         continue;
4613                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4614         }
4615         for (i = 0;i < r_refdef.scene.numlights;i++)
4616         {
4617                 rtlight = r_refdef.scene.lights[i];
4618                 rtlight->corona_visibility = 0;
4619                 rtlight->corona_queryindex_visiblepixels = 0;
4620                 rtlight->corona_queryindex_allpixels = 0;
4621                 if (!(rtlight->flags & flag))
4622                         continue;
4623                 if (rtlight->corona <= 0)
4624                         continue;
4625                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4626         }
4627         if (usequery)
4628                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4629
4630         // now draw the coronas using the query data for intensity info
4631         for (lightindex = 0;lightindex < range;lightindex++)
4632         {
4633                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4634                 if (!light)
4635                         continue;
4636                 rtlight = &light->rtlight;
4637                 if (rtlight->corona_visibility <= 0)
4638                         continue;
4639                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4640         }
4641         for (i = 0;i < r_refdef.scene.numlights;i++)
4642         {
4643                 rtlight = r_refdef.scene.lights[i];
4644                 if (rtlight->corona_visibility <= 0)
4645                         continue;
4646                 if (gl_flashblend.integer)
4647                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4648                 else
4649                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4650         }
4651 }
4652
4653
4654
4655 static dlight_t *R_Shadow_NewWorldLight(void)
4656 {
4657         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4658 }
4659
4660 static void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
4661 {
4662         matrix4x4_t matrix;
4663
4664         // note that style is no longer validated here, -1 is used for unstyled lights and >= MAX_LIGHTSTYLES is accepted for sake of editing rtlights files that might be out of bounds but perfectly formatted
4665
4666         // validate parameters
4667         if (!cubemapname)
4668                 cubemapname = "";
4669
4670         // copy to light properties
4671         VectorCopy(origin, light->origin);
4672         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4673         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4674         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4675         /*
4676         light->color[0] = max(color[0], 0);
4677         light->color[1] = max(color[1], 0);
4678         light->color[2] = max(color[2], 0);
4679         */
4680         light->color[0] = color[0];
4681         light->color[1] = color[1];
4682         light->color[2] = color[2];
4683         light->radius = max(radius, 0);
4684         light->style = style;
4685         light->shadow = shadowenable;
4686         light->corona = corona;
4687         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4688         light->coronasizescale = coronasizescale;
4689         light->ambientscale = ambientscale;
4690         light->diffusescale = diffusescale;
4691         light->specularscale = specularscale;
4692         light->flags = flags;
4693
4694         // update renderable light data
4695         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4696         R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
4697 }
4698
4699 static void R_Shadow_FreeWorldLight(dlight_t *light)
4700 {
4701         if (r_shadow_selectedlight == light)
4702                 r_shadow_selectedlight = NULL;
4703         R_RTLight_Uncompile(&light->rtlight);
4704         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4705 }
4706
4707 void R_Shadow_ClearWorldLights(void)
4708 {
4709         size_t lightindex;
4710         dlight_t *light;
4711         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4712         for (lightindex = 0;lightindex < range;lightindex++)
4713         {
4714                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4715                 if (light)
4716                         R_Shadow_FreeWorldLight(light);
4717         }
4718         r_shadow_selectedlight = NULL;
4719 }
4720
4721 static void R_Shadow_SelectLight(dlight_t *light)
4722 {
4723         if (r_shadow_selectedlight)
4724                 r_shadow_selectedlight->selected = false;
4725         r_shadow_selectedlight = light;
4726         if (r_shadow_selectedlight)
4727                 r_shadow_selectedlight->selected = true;
4728 }
4729
4730 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4731 {
4732         // this is never batched (there can be only one)
4733         float vertex3f[12];
4734         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4735         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4736         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4737 }
4738
4739 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4740 {
4741         float intensity;
4742         float s;
4743         vec3_t spritecolor;
4744         skinframe_t *skinframe;
4745         float vertex3f[12];
4746
4747         // this is never batched (due to the ent parameter changing every time)
4748         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4749         const dlight_t *light = (dlight_t *)ent;
4750         s = EDLIGHTSPRSIZE;
4751
4752         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4753
4754         intensity = 0.5f;
4755         VectorScale(light->color, intensity, spritecolor);
4756         if (VectorLength(spritecolor) < 0.1732f)
4757                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4758         if (VectorLength(spritecolor) > 1.0f)
4759                 VectorNormalize(spritecolor);
4760
4761         // draw light sprite
4762         if (light->cubemapname[0] && !light->shadow)
4763                 skinframe = r_editlights_sprcubemapnoshadowlight;
4764         else if (light->cubemapname[0])
4765                 skinframe = r_editlights_sprcubemaplight;
4766         else if (!light->shadow)
4767                 skinframe = r_editlights_sprnoshadowlight;
4768         else
4769                 skinframe = r_editlights_sprlight;
4770
4771         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4772         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4773
4774         // draw selection sprite if light is selected
4775         if (light->selected)
4776         {
4777                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4778                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4779                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4780         }
4781 }
4782
4783 void R_Shadow_DrawLightSprites(void)
4784 {
4785         size_t lightindex;
4786         dlight_t *light;
4787         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4788         for (lightindex = 0;lightindex < range;lightindex++)
4789         {
4790                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4791                 if (light)
4792                         R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4793         }
4794         if (!r_editlights_lockcursor)
4795                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4796 }
4797
4798 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4799 {
4800         unsigned int range;
4801         dlight_t *light;
4802         rtlight_t *rtlight;
4803         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4804         if (lightindex >= range)
4805                 return -1;
4806         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4807         if (!light)
4808                 return 0;
4809         rtlight = &light->rtlight;
4810         //if (!(rtlight->flags & flag))
4811         //      return 0;
4812         VectorCopy(rtlight->shadoworigin, origin);
4813         *radius = rtlight->radius;
4814         VectorCopy(rtlight->color, color);
4815         return 1;
4816 }
4817
4818 static void R_Shadow_SelectLightInView(void)
4819 {
4820         float bestrating, rating, temp[3];
4821         dlight_t *best;
4822         size_t lightindex;
4823         dlight_t *light;
4824         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4825         best = NULL;
4826         bestrating = 0;
4827
4828         if (r_editlights_lockcursor)
4829                 return;
4830         for (lightindex = 0;lightindex < range;lightindex++)
4831         {
4832                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4833                 if (!light)
4834                         continue;
4835                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4836                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4837                 if (rating >= 0.95)
4838                 {
4839                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4840                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
4841                         {
4842                                 bestrating = rating;
4843                                 best = light;
4844                         }
4845                 }
4846         }
4847         R_Shadow_SelectLight(best);
4848 }
4849
4850 void R_Shadow_LoadWorldLights(void)
4851 {
4852         int n, a, style, shadow, flags;
4853         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4854         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4855         if (cl.worldmodel == NULL)
4856         {
4857                 Con_Print("No map loaded.\n");
4858                 return;
4859         }
4860         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4861         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4862         if (lightsstring)
4863         {
4864                 s = lightsstring;
4865                 n = 0;
4866                 while (*s)
4867                 {
4868                         /*
4869                         t = s;
4870                         shadow = true;
4871                         for (;COM_Parse(t, true) && strcmp(
4872                         if (COM_Parse(t, true))
4873                         {
4874                                 if (com_token[0] == '!')
4875                                 {
4876                                         shadow = false;
4877                                         origin[0] = atof(com_token+1);
4878                                 }
4879                                 else
4880                                         origin[0] = atof(com_token);
4881                                 if (Com_Parse(t
4882                         }
4883                         */
4884                         t = s;
4885                         while (*s && *s != '\n' && *s != '\r')
4886                                 s++;
4887                         if (!*s)
4888                                 break;
4889                         tempchar = *s;
4890                         shadow = true;
4891                         // check for modifier flags
4892                         if (*t == '!')
4893                         {
4894                                 shadow = false;
4895                                 t++;
4896                         }
4897                         *s = 0;
4898 #if _MSC_VER >= 1400
4899 #define sscanf sscanf_s
4900 #endif
4901                         cubemapname[sizeof(cubemapname)-1] = 0;
4902 #if MAX_QPATH != 128
4903 #error update this code if MAX_QPATH changes
4904 #endif
4905                         a = sscanf(t, "%f %f %f %f %f %f %f %d %127s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname
4906 #if _MSC_VER >= 1400
4907 , (unsigned int)sizeof(cubemapname)
4908 #endif
4909 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4910                         *s = tempchar;
4911                         if (a < 18)
4912                                 flags = LIGHTFLAG_REALTIMEMODE;
4913                         if (a < 17)
4914                                 specularscale = 1;
4915                         if (a < 16)
4916                                 diffusescale = 1;
4917                         if (a < 15)
4918                                 ambientscale = 0;
4919                         if (a < 14)
4920                                 coronasizescale = 0.25f;
4921                         if (a < 13)
4922                                 VectorClear(angles);
4923                         if (a < 10)
4924                                 corona = 0;
4925                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4926                                 cubemapname[0] = 0;
4927                         // remove quotes on cubemapname
4928                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4929                         {
4930                                 size_t namelen;
4931                                 namelen = strlen(cubemapname) - 2;
4932                                 memmove(cubemapname, cubemapname + 1, namelen);
4933                                 cubemapname[namelen] = '\0';
4934                         }
4935                         if (a < 8)
4936                         {
4937                                 Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
4938                                 break;
4939                         }
4940                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4941                         if (*s == '\r')
4942                                 s++;
4943                         if (*s == '\n')
4944                                 s++;
4945                         n++;
4946                 }
4947                 if (*s)
4948                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4949                 Mem_Free(lightsstring);
4950         }
4951 }
4952
4953 void R_Shadow_SaveWorldLights(void)
4954 {
4955         size_t lightindex;
4956         dlight_t *light;
4957         size_t bufchars, bufmaxchars;
4958         char *buf, *oldbuf;
4959         char name[MAX_QPATH];
4960         char line[MAX_INPUTLINE];
4961         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4962         // I hate lines which are 3 times my screen size :( --blub
4963         if (!range)
4964                 return;
4965         if (cl.worldmodel == NULL)
4966         {
4967                 Con_Print("No map loaded.\n");
4968                 return;
4969         }
4970         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4971         bufchars = bufmaxchars = 0;
4972         buf = NULL;
4973         for (lightindex = 0;lightindex < range;lightindex++)
4974         {
4975                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4976                 if (!light)
4977                         continue;
4978                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4979                         dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
4980                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4981                         dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
4982                 else
4983                         dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style);
4984                 if (bufchars + strlen(line) > bufmaxchars)
4985                 {
4986                         bufmaxchars = bufchars + strlen(line) + 2048;
4987                         oldbuf = buf;
4988                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4989                         if (oldbuf)
4990                         {
4991                                 if (bufchars)
4992                                         memcpy(buf, oldbuf, bufchars);
4993                                 Mem_Free(oldbuf);
4994                         }
4995                 }
4996                 if (strlen(line))
4997                 {
4998                         memcpy(buf + bufchars, line, strlen(line));
4999                         bufchars += strlen(line);
5000                 }
5001         }
5002         if (bufchars)
5003                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5004         if (buf)
5005                 Mem_Free(buf);
5006 }
5007
5008 void R_Shadow_LoadLightsFile(void)
5009 {
5010         int n, a, style;
5011         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5012         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5013         if (cl.worldmodel == NULL)
5014         {
5015                 Con_Print("No map loaded.\n");
5016                 return;
5017         }
5018         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5019         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5020         if (lightsstring)
5021         {
5022                 s = lightsstring;
5023                 n = 0;
5024                 while (*s)
5025                 {
5026                         t = s;
5027                         while (*s && *s != '\n' && *s != '\r')
5028                                 s++;
5029                         if (!*s)
5030                                 break;
5031                         tempchar = *s;
5032                         *s = 0;
5033                         a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
5034                         *s = tempchar;
5035                         if (a < 14)
5036                         {
5037                                 Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
5038                                 break;
5039                         }
5040                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5041                         radius = bound(15, radius, 4096);
5042                         VectorScale(color, (2.0f / (8388608.0f)), color);
5043                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5044                         if (*s == '\r')
5045                                 s++;
5046                         if (*s == '\n')
5047                                 s++;
5048                         n++;
5049                 }
5050                 if (*s)
5051                         Con_Printf("invalid lights file \"%s\"\n", name);
5052                 Mem_Free(lightsstring);
5053         }
5054 }
5055
5056 // tyrlite/hmap2 light types in the delay field
5057 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5058
5059 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5060 {
5061         int entnum;
5062         int style;
5063         int islight;
5064         int skin;
5065         int pflags;
5066         //int effects;
5067         int type;
5068         int n;
5069         char *entfiledata;
5070         const char *data;
5071         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5072         char key[256], value[MAX_INPUTLINE];
5073         char vabuf[1024];
5074
5075         if (cl.worldmodel == NULL)
5076         {
5077                 Con_Print("No map loaded.\n");
5078                 return;
5079         }
5080         // try to load a .ent file first
5081         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5082         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5083         // and if that is not found, fall back to the bsp file entity string
5084         if (!data)
5085                 data = cl.worldmodel->brush.entities;
5086         if (!data)
5087                 return;
5088         for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5089         {
5090                 type = LIGHTTYPE_MINUSX;
5091                 origin[0] = origin[1] = origin[2] = 0;
5092                 originhack[0] = originhack[1] = originhack[2] = 0;
5093                 angles[0] = angles[1] = angles[2] = 0;
5094                 color[0] = color[1] = color[2] = 1;
5095                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5096                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5097                 fadescale = 1;
5098                 lightscale = 1;
5099                 style = 0;
5100                 skin = 0;
5101                 pflags = 0;
5102                 //effects = 0;
5103                 islight = false;
5104                 while (1)
5105                 {
5106                         if (!COM_ParseToken_Simple(&data, false, false, true))
5107                                 break; // error
5108                         if (com_token[0] == '}')
5109                                 break; // end of entity
5110                         if (com_token[0] == '_')
5111                                 strlcpy(key, com_token + 1, sizeof(key));
5112                         else
5113                                 strlcpy(key, com_token, sizeof(key));
5114                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5115                                 key[strlen(key)-1] = 0;
5116                         if (!COM_ParseToken_Simple(&data, false, false, true))
5117                                 break; // error
5118                         strlcpy(value, com_token, sizeof(value));
5119
5120                         // now that we have the key pair worked out...
5121                         if (!strcmp("light", key))
5122                         {
5123                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5124                                 if (n == 1)
5125                                 {
5126                                         // quake
5127                                         light[0] = vec[0] * (1.0f / 256.0f);
5128                                         light[1] = vec[0] * (1.0f / 256.0f);
5129                                         light[2] = vec[0] * (1.0f / 256.0f);
5130                                         light[3] = vec[0];
5131                                 }
5132                                 else if (n == 4)
5133                                 {
5134                                         // halflife
5135                                         light[0] = vec[0] * (1.0f / 255.0f);
5136                                         light[1] = vec[1] * (1.0f / 255.0f);
5137                                         light[2] = vec[2] * (1.0f / 255.0f);
5138                                         light[3] = vec[3];
5139                                 }
5140                         }
5141                         else if (!strcmp("delay", key))
5142                                 type = atoi(value);
5143                         else if (!strcmp("origin", key))
5144                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5145                         else if (!strcmp("angle", key))
5146                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5147                         else if (!strcmp("angles", key))
5148                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5149                         else if (!strcmp("color", key))
5150                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5151                         else if (!strcmp("wait", key))
5152                                 fadescale = atof(value);
5153                         else if (!strcmp("classname", key))
5154                         {
5155                                 if (!strncmp(value, "light", 5))
5156                                 {
5157                                         islight = true;
5158                                         if (!strcmp(value, "light_fluoro"))
5159                                         {
5160                                                 originhack[0] = 0;
5161                                                 originhack[1] = 0;
5162                                                 originhack[2] = 0;
5163                                                 overridecolor[0] = 1;
5164                                                 overridecolor[1] = 1;
5165                                                 overridecolor[2] = 1;
5166                                         }
5167                                         if (!strcmp(value, "light_fluorospark"))
5168                                         {
5169                                                 originhack[0] = 0;
5170                                                 originhack[1] = 0;
5171                                                 originhack[2] = 0;
5172                                                 overridecolor[0] = 1;
5173                                                 overridecolor[1] = 1;
5174                                                 overridecolor[2] = 1;
5175                                         }
5176                                         if (!strcmp(value, "light_globe"))
5177                                         {
5178                                                 originhack[0] = 0;
5179                                                 originhack[1] = 0;
5180                                                 originhack[2] = 0;
5181                                                 overridecolor[0] = 1;
5182                                                 overridecolor[1] = 0.8;
5183                                                 overridecolor[2] = 0.4;
5184                                         }
5185                                         if (!strcmp(value, "light_flame_large_yellow"))
5186                                         {
5187                                                 originhack[0] = 0;
5188                                                 originhack[1] = 0;
5189                                                 originhack[2] = 0;
5190                                                 overridecolor[0] = 1;
5191                                                 overridecolor[1] = 0.5;
5192                                                 overridecolor[2] = 0.1;
5193                                         }
5194                                         if (!strcmp(value, "light_flame_small_yellow"))
5195                                         {
5196                                                 originhack[0] = 0;
5197                                                 originhack[1] = 0;
5198                                                 originhack[2] = 0;
5199                                                 overridecolor[0] = 1;
5200                                                 overridecolor[1] = 0.5;
5201                                                 overridecolor[2] = 0.1;
5202                                         }
5203                                         if (!strcmp(value, "light_torch_small_white"))
5204                                         {
5205                                                 originhack[0] = 0;
5206                                                 originhack[1] = 0;
5207                                                 originhack[2] = 0;
5208                                                 overridecolor[0] = 1;
5209                                                 overridecolor[1] = 0.5;
5210                                                 overridecolor[2] = 0.1;
5211                                         }
5212                                         if (!strcmp(value, "light_torch_small_walltorch"))
5213                                         {
5214                                                 originhack[0] = 0;
5215                                                 originhack[1] = 0;
5216                                                 originhack[2] = 0;
5217                                                 overridecolor[0] = 1;
5218                                                 overridecolor[1] = 0.5;
5219                                                 overridecolor[2] = 0.1;
5220                                         }
5221                                 }
5222                         }
5223                         else if (!strcmp("style", key))
5224                                 style = atoi(value);
5225                         else if (!strcmp("skin", key))
5226                                 skin = (int)atof(value);
5227                         else if (!strcmp("pflags", key))
5228                                 pflags = (int)atof(value);
5229                         //else if (!strcmp("effects", key))
5230                         //      effects = (int)atof(value);
5231                         else if (cl.worldmodel->type == mod_brushq3)
5232                         {
5233                                 if (!strcmp("scale", key))
5234                                         lightscale = atof(value);
5235                                 if (!strcmp("fade", key))
5236                                         fadescale = atof(value);
5237                         }
5238                 }
5239                 if (!islight)
5240                         continue;
5241                 if (lightscale <= 0)
5242                         lightscale = 1;
5243                 if (fadescale <= 0)
5244                         fadescale = 1;
5245                 if (color[0] == color[1] && color[0] == color[2])
5246                 {
5247                         color[0] *= overridecolor[0];
5248                         color[1] *= overridecolor[1];
5249                         color[2] *= overridecolor[2];
5250                 }
5251                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5252                 color[0] = color[0] * light[0];
5253                 color[1] = color[1] * light[1];
5254                 color[2] = color[2] * light[2];
5255                 switch (type)
5256                 {
5257                 case LIGHTTYPE_MINUSX:
5258                         break;
5259                 case LIGHTTYPE_RECIPX:
5260                         radius *= 2;
5261                         VectorScale(color, (1.0f / 16.0f), color);
5262                         break;
5263                 case LIGHTTYPE_RECIPXX:
5264                         radius *= 2;
5265                         VectorScale(color, (1.0f / 16.0f), color);
5266                         break;
5267                 default:
5268                 case LIGHTTYPE_NONE:
5269                         break;
5270                 case LIGHTTYPE_SUN:
5271                         break;
5272                 case LIGHTTYPE_MINUSXX:
5273                         break;
5274                 }
5275                 VectorAdd(origin, originhack, origin);
5276                 if (radius >= 1)
5277                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5278         }
5279         if (entfiledata)
5280                 Mem_Free(entfiledata);
5281 }
5282
5283
5284 static void R_Shadow_SetCursorLocationForView(void)
5285 {
5286         vec_t dist, push;
5287         vec3_t dest, endpos;
5288         trace_t trace;
5289         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5290         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5291         if (trace.fraction < 1)
5292         {
5293                 dist = trace.fraction * r_editlights_cursordistance.value;
5294                 push = r_editlights_cursorpushback.value;
5295                 if (push > dist)
5296                         push = dist;
5297                 push = -push;
5298                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5299                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5300         }
5301         else
5302         {
5303                 VectorClear( endpos );
5304         }
5305         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5306         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5307         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5308 }
5309
5310 void R_Shadow_UpdateWorldLightSelection(void)
5311 {
5312         if (r_editlights.integer)
5313         {
5314                 R_Shadow_SetCursorLocationForView();
5315                 R_Shadow_SelectLightInView();
5316         }
5317         else
5318                 R_Shadow_SelectLight(NULL);
5319 }
5320
5321 static void R_Shadow_EditLights_Clear_f(void)
5322 {
5323         R_Shadow_ClearWorldLights();
5324 }
5325
5326 void R_Shadow_EditLights_Reload_f(void)
5327 {
5328         if (!cl.worldmodel)
5329                 return;
5330         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5331         R_Shadow_ClearWorldLights();
5332         if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5333         {
5334                 R_Shadow_LoadWorldLights();
5335                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5336                         R_Shadow_LoadLightsFile();
5337         }
5338         if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5339         {
5340                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5341                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5342         }
5343 }
5344
5345 static void R_Shadow_EditLights_Save_f(void)
5346 {
5347         if (!cl.worldmodel)
5348                 return;
5349         R_Shadow_SaveWorldLights();
5350 }
5351
5352 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5353 {
5354         R_Shadow_ClearWorldLights();
5355         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5356 }
5357
5358 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5359 {
5360         R_Shadow_ClearWorldLights();
5361         R_Shadow_LoadLightsFile();
5362 }
5363
5364 static void R_Shadow_EditLights_Spawn_f(void)
5365 {
5366         vec3_t color;
5367         if (!r_editlights.integer)
5368         {
5369                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5370                 return;
5371         }
5372         if (Cmd_Argc() != 1)
5373         {
5374                 Con_Print("r_editlights_spawn does not take parameters\n");
5375                 return;
5376         }
5377         color[0] = color[1] = color[2] = 1;
5378         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5379 }
5380
5381 static void R_Shadow_EditLights_Edit_f(void)
5382 {
5383         vec3_t origin, angles, color;
5384         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5385         int style, shadows, flags, normalmode, realtimemode;
5386         char cubemapname[MAX_INPUTLINE];
5387         if (!r_editlights.integer)
5388         {
5389                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5390                 return;
5391         }
5392         if (!r_shadow_selectedlight)
5393         {
5394                 Con_Print("No selected light.\n");
5395                 return;
5396         }
5397         VectorCopy(r_shadow_selectedlight->origin, origin);
5398         VectorCopy(r_shadow_selectedlight->angles, angles);
5399         VectorCopy(r_shadow_selectedlight->color, color);
5400         radius = r_shadow_selectedlight->radius;
5401         style = r_shadow_selectedlight->style;
5402         if (r_shadow_selectedlight->cubemapname)
5403                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5404         else
5405                 cubemapname[0] = 0;
5406         shadows = r_shadow_selectedlight->shadow;
5407         corona = r_shadow_selectedlight->corona;
5408         coronasizescale = r_shadow_selectedlight->coronasizescale;
5409         ambientscale = r_shadow_selectedlight->ambientscale;
5410         diffusescale = r_shadow_selectedlight->diffusescale;
5411         specularscale = r_shadow_selectedlight->specularscale;
5412         flags = r_shadow_selectedlight->flags;
5413         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5414         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5415         if (!strcmp(Cmd_Argv(1), "origin"))
5416         {
5417                 if (Cmd_Argc() != 5)
5418                 {
5419                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5420                         return;
5421                 }
5422                 origin[0] = atof(Cmd_Argv(2));
5423                 origin[1] = atof(Cmd_Argv(3));
5424                 origin[2] = atof(Cmd_Argv(4));
5425         }
5426         else if (!strcmp(Cmd_Argv(1), "originscale"))
5427         {
5428                 if (Cmd_Argc() != 5)
5429                 {
5430                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5431                         return;
5432                 }
5433                 origin[0] *= atof(Cmd_Argv(2));
5434                 origin[1] *= atof(Cmd_Argv(3));
5435                 origin[2] *= atof(Cmd_Argv(4));
5436         }
5437         else if (!strcmp(Cmd_Argv(1), "originx"))
5438         {
5439                 if (Cmd_Argc() != 3)
5440                 {
5441                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5442                         return;
5443                 }
5444                 origin[0] = atof(Cmd_Argv(2));
5445         }
5446         else if (!strcmp(Cmd_Argv(1), "originy"))
5447         {
5448                 if (Cmd_Argc() != 3)
5449                 {
5450                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5451                         return;
5452                 }
5453                 origin[1] = atof(Cmd_Argv(2));
5454         }
5455         else if (!strcmp(Cmd_Argv(1), "originz"))
5456         {
5457                 if (Cmd_Argc() != 3)
5458                 {
5459                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5460                         return;
5461                 }
5462                 origin[2] = atof(Cmd_Argv(2));
5463         }
5464         else if (!strcmp(Cmd_Argv(1), "move"))
5465         {
5466                 if (Cmd_Argc() != 5)
5467                 {
5468                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5469                         return;
5470                 }
5471                 origin[0] += atof(Cmd_Argv(2));
5472                 origin[1] += atof(Cmd_Argv(3));
5473                 origin[2] += atof(Cmd_Argv(4));
5474         }
5475         else if (!strcmp(Cmd_Argv(1), "movex"))
5476         {
5477                 if (Cmd_Argc() != 3)
5478                 {
5479                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5480                         return;
5481                 }
5482                 origin[0] += atof(Cmd_Argv(2));
5483         }
5484         else if (!strcmp(Cmd_Argv(1), "movey"))
5485         {
5486                 if (Cmd_Argc() != 3)
5487                 {
5488                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5489                         return;
5490                 }
5491                 origin[1] += atof(Cmd_Argv(2));
5492         }
5493         else if (!strcmp(Cmd_Argv(1), "movez"))
5494         {
5495                 if (Cmd_Argc() != 3)
5496                 {
5497                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5498                         return;
5499                 }
5500                 origin[2] += atof(Cmd_Argv(2));
5501         }
5502         else if (!strcmp(Cmd_Argv(1), "angles"))
5503         {
5504                 if (Cmd_Argc() != 5)
5505                 {
5506                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5507                         return;
5508                 }
5509                 angles[0] = atof(Cmd_Argv(2));
5510                 angles[1] = atof(Cmd_Argv(3));
5511                 angles[2] = atof(Cmd_Argv(4));
5512         }
5513         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5514         {
5515                 if (Cmd_Argc() != 3)
5516                 {
5517                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5518                         return;
5519                 }
5520                 angles[0] = atof(Cmd_Argv(2));
5521         }
5522         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5523         {
5524                 if (Cmd_Argc() != 3)
5525                 {
5526                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5527                         return;
5528                 }
5529                 angles[1] = atof(Cmd_Argv(2));
5530         }
5531         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5532         {
5533                 if (Cmd_Argc() != 3)
5534                 {
5535                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5536                         return;
5537                 }
5538                 angles[2] = atof(Cmd_Argv(2));
5539         }
5540         else if (!strcmp(Cmd_Argv(1), "color"))
5541         {
5542                 if (Cmd_Argc() != 5)
5543                 {
5544                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5545                         return;
5546                 }
5547                 color[0] = atof(Cmd_Argv(2));
5548                 color[1] = atof(Cmd_Argv(3));
5549                 color[2] = atof(Cmd_Argv(4));
5550         }
5551         else if (!strcmp(Cmd_Argv(1), "radius"))
5552         {
5553                 if (Cmd_Argc() != 3)
5554                 {
5555                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5556                         return;
5557                 }
5558                 radius = atof(Cmd_Argv(2));
5559         }
5560         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5561         {
5562                 if (Cmd_Argc() == 3)
5563                 {
5564                         double scale = atof(Cmd_Argv(2));
5565                         color[0] *= scale;
5566                         color[1] *= scale;
5567                         color[2] *= scale;
5568                 }
5569                 else
5570                 {
5571                         if (Cmd_Argc() != 5)
5572                         {
5573                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5574                                 return;
5575                         }
5576                         color[0] *= atof(Cmd_Argv(2));
5577                         color[1] *= atof(Cmd_Argv(3));
5578                         color[2] *= atof(Cmd_Argv(4));
5579                 }
5580         }
5581         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5582         {
5583                 if (Cmd_Argc() != 3)
5584                 {
5585                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5586                         return;
5587                 }
5588                 radius *= atof(Cmd_Argv(2));
5589         }
5590         else if (!strcmp(Cmd_Argv(1), "style"))
5591         {
5592                 if (Cmd_Argc() != 3)
5593                 {
5594                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5595                         return;
5596                 }
5597                 style = atoi(Cmd_Argv(2));
5598         }
5599         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5600         {
5601                 if (Cmd_Argc() > 3)
5602                 {
5603                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5604                         return;
5605                 }
5606                 if (Cmd_Argc() == 3)
5607                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5608                 else
5609                         cubemapname[0] = 0;
5610         }
5611         else if (!strcmp(Cmd_Argv(1), "shadows"))
5612         {
5613                 if (Cmd_Argc() != 3)
5614                 {
5615                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5616                         return;
5617                 }
5618                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5619         }
5620         else if (!strcmp(Cmd_Argv(1), "corona"))
5621         {
5622                 if (Cmd_Argc() != 3)
5623                 {
5624                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5625                         return;
5626                 }
5627                 corona = atof(Cmd_Argv(2));
5628         }
5629         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5630         {
5631                 if (Cmd_Argc() != 3)
5632                 {
5633                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5634                         return;
5635                 }
5636                 coronasizescale = atof(Cmd_Argv(2));
5637         }
5638         else if (!strcmp(Cmd_Argv(1), "ambient"))
5639         {
5640                 if (Cmd_Argc() != 3)
5641                 {
5642                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5643                         return;
5644                 }
5645                 ambientscale = atof(Cmd_Argv(2));
5646         }
5647         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5648         {
5649                 if (Cmd_Argc() != 3)
5650                 {
5651                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5652                         return;
5653                 }
5654                 diffusescale = atof(Cmd_Argv(2));
5655         }
5656         else if (!strcmp(Cmd_Argv(1), "specular"))
5657         {
5658                 if (Cmd_Argc() != 3)
5659                 {
5660                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5661                         return;
5662                 }
5663                 specularscale = atof(Cmd_Argv(2));
5664         }
5665         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5666         {
5667                 if (Cmd_Argc() != 3)
5668                 {
5669                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5670                         return;
5671                 }
5672                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5673         }
5674         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5675         {
5676                 if (Cmd_Argc() != 3)
5677                 {
5678                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5679                         return;
5680                 }
5681                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5682         }
5683         else
5684         {
5685                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5686                 Con_Print("Selected light's properties:\n");
5687                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5688                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5689                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5690                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5691                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5692                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5693                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5694                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5695                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5696                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5697                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5698                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5699                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5700                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5701                 return;
5702         }
5703         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5704         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5705 }
5706
5707 static void R_Shadow_EditLights_EditAll_f(void)
5708 {
5709         size_t lightindex;
5710         dlight_t *light, *oldselected;
5711         size_t range;
5712
5713         if (!r_editlights.integer)
5714         {
5715                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5716                 return;
5717         }
5718
5719         oldselected = r_shadow_selectedlight;
5720         // EditLights doesn't seem to have a "remove" command or something so:
5721         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5722         for (lightindex = 0;lightindex < range;lightindex++)
5723         {
5724                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5725                 if (!light)
5726                         continue;
5727                 R_Shadow_SelectLight(light);
5728                 R_Shadow_EditLights_Edit_f();
5729         }
5730         // return to old selected (to not mess editing once selection is locked)
5731         R_Shadow_SelectLight(oldselected);
5732 }
5733
5734 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5735 {
5736         int lightnumber, lightcount;
5737         size_t lightindex, range;
5738         dlight_t *light;
5739         char temp[256];
5740         float x, y;
5741
5742         if (!r_editlights.integer)
5743                 return;
5744
5745         // update cvars so QC can query them
5746         if (r_shadow_selectedlight)
5747         {
5748                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5749                 Cvar_SetQuick(&r_editlights_current_origin, temp);
5750                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5751                 Cvar_SetQuick(&r_editlights_current_angles, temp);
5752                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5753                 Cvar_SetQuick(&r_editlights_current_color, temp);
5754                 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5755                 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5756                 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5757                 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5758                 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5759                 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5760                 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5761                 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5762                 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5763                 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5764                 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5765         }
5766
5767         // draw properties on screen
5768         if (!r_editlights_drawproperties.integer)
5769                 return;
5770         x = vid_conwidth.value - 320;
5771         y = 5;
5772         DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5773         lightnumber = -1;
5774         lightcount = 0;
5775         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5776         for (lightindex = 0;lightindex < range;lightindex++)
5777         {
5778                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5779                 if (!light)
5780                         continue;
5781                 if (light == r_shadow_selectedlight)
5782                         lightnumber = (int)lightindex;
5783                 lightcount++;
5784         }
5785         dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5786         dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5787         y += 8;
5788         if (r_shadow_selectedlight == NULL)
5789                 return;
5790         dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5791         dpsnprintf(temp, sizeof(temp), "Origin       : %.0f %.0f %.0f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5792         dpsnprintf(temp, sizeof(temp), "Angles       : %.0f %.0f %.0f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5793         dpsnprintf(temp, sizeof(temp), "Color        : %.2f %.2f %.2f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5794         dpsnprintf(temp, sizeof(temp), "Radius       : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5795         dpsnprintf(temp, sizeof(temp), "Corona       : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5796         dpsnprintf(temp, sizeof(temp), "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5797         dpsnprintf(temp, sizeof(temp), "Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5798         dpsnprintf(temp, sizeof(temp), "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5799         dpsnprintf(temp, sizeof(temp), "CoronaSize   : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5800         dpsnprintf(temp, sizeof(temp), "Ambient      : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5801         dpsnprintf(temp, sizeof(temp), "Diffuse      : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5802         dpsnprintf(temp, sizeof(temp), "Specular     : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5803         dpsnprintf(temp, sizeof(temp), "NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5804         dpsnprintf(temp, sizeof(temp), "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5805         y += 8;
5806         dpsnprintf(temp, sizeof(temp), "Render stats\n"); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5807         dpsnprintf(temp, sizeof(temp), "Current color: %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.currentcolor[0], r_shadow_selectedlight->rtlight.currentcolor[1], r_shadow_selectedlight->rtlight.currentcolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5808         dpsnprintf(temp, sizeof(temp), "Shadow size  : %ix%ix6\n", r_shadow_selectedlight->rtlight.shadowmapatlassidesize, r_shadow_selectedlight->rtlight.shadowmapatlassidesize); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5809         dpsnprintf(temp, sizeof(temp), "World surfs  : %i\n", r_shadow_selectedlight->rtlight.cached_numsurfaces); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5810         dpsnprintf(temp, sizeof(temp), "Shadow ents  : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numshadowentities, r_shadow_selectedlight->rtlight.cached_numshadowentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5811         dpsnprintf(temp, sizeof(temp), "Lit ents     : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numlightentities, r_shadow_selectedlight->rtlight.cached_numlightentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5812         dpsnprintf(temp, sizeof(temp), "BG photons   : %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photons); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5813         dpsnprintf(temp, sizeof(temp), "BG radius    : %.0f\n", r_shadow_selectedlight->rtlight.bouncegrid_effectiveradius); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5814         dpsnprintf(temp, sizeof(temp), "BG color     : %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[0], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[1], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5815         dpsnprintf(temp, sizeof(temp), "BG stats     : %i traces %i hits\n", r_shadow_selectedlight->rtlight.bouncegrid_traces, r_shadow_selectedlight->rtlight.bouncegrid_hits); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5816 }
5817
5818 static void R_Shadow_EditLights_ToggleShadow_f(void)
5819 {
5820         if (!r_editlights.integer)
5821         {
5822                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5823                 return;
5824         }
5825         if (!r_shadow_selectedlight)
5826         {
5827                 Con_Print("No selected light.\n");
5828                 return;
5829         }
5830         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
5831 }
5832
5833 static void R_Shadow_EditLights_ToggleCorona_f(void)
5834 {
5835         if (!r_editlights.integer)
5836         {
5837                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5838                 return;
5839         }
5840         if (!r_shadow_selectedlight)
5841         {
5842                 Con_Print("No selected light.\n");
5843                 return;
5844         }
5845         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
5846 }
5847
5848 static void R_Shadow_EditLights_Remove_f(void)
5849 {
5850         if (!r_editlights.integer)
5851         {
5852                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5853                 return;
5854         }
5855         if (!r_shadow_selectedlight)
5856         {
5857                 Con_Print("No selected light.\n");
5858                 return;
5859         }
5860         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5861         r_shadow_selectedlight = NULL;
5862 }
5863
5864 static void R_Shadow_EditLights_Help_f(void)
5865 {
5866         Con_Print(
5867 "Documentation on r_editlights system:\n"
5868 "Settings:\n"
5869 "r_editlights : enable/disable editing mode\n"
5870 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5871 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5872 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5873 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5874 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5875 "Commands:\n"
5876 "r_editlights_help : this help\n"
5877 "r_editlights_clear : remove all lights\n"
5878 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5879 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5880 "r_editlights_save : save to .rtlights file\n"
5881 "r_editlights_spawn : create a light with default settings\n"
5882 "r_editlights_edit command : edit selected light - more documentation below\n"
5883 "r_editlights_remove : remove selected light\n"
5884 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5885 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5886 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5887 "Edit commands:\n"
5888 "origin x y z : set light location\n"
5889 "originx x: set x component of light location\n"
5890 "originy y: set y component of light location\n"
5891 "originz z: set z component of light location\n"
5892 "move x y z : adjust light location\n"
5893 "movex x: adjust x component of light location\n"
5894 "movey y: adjust y component of light location\n"
5895 "movez z: adjust z component of light location\n"
5896 "angles x y z : set light angles\n"
5897 "anglesx x: set x component of light angles\n"
5898 "anglesy y: set y component of light angles\n"
5899 "anglesz z: set z component of light angles\n"
5900 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5901 "radius radius : set radius (size) of light\n"
5902 "colorscale grey : multiply color of light (1 does nothing)\n"
5903 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5904 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5905 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5906 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5907 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5908 "cubemap basename : set filter cubemap of light\n"
5909 "shadows 1/0 : turn on/off shadows\n"
5910 "corona n : set corona intensity\n"
5911 "coronasize n : set corona size (0-1)\n"
5912 "ambient n : set ambient intensity (0-1)\n"
5913 "diffuse n : set diffuse intensity (0-1)\n"
5914 "specular n : set specular intensity (0-1)\n"
5915 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5916 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5917 "<nothing> : print light properties to console\n"
5918         );
5919 }
5920
5921 static void R_Shadow_EditLights_CopyInfo_f(void)
5922 {
5923         if (!r_editlights.integer)
5924         {
5925                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5926                 return;
5927         }
5928         if (!r_shadow_selectedlight)
5929         {
5930                 Con_Print("No selected light.\n");
5931                 return;
5932         }
5933         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5934         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5935         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5936         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5937         if (r_shadow_selectedlight->cubemapname)
5938                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5939         else
5940                 r_shadow_bufferlight.cubemapname[0] = 0;
5941         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5942         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5943         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5944         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5945         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5946         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5947         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5948 }
5949
5950 static void R_Shadow_EditLights_PasteInfo_f(void)
5951 {
5952         if (!r_editlights.integer)
5953         {
5954                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5955                 return;
5956         }
5957         if (!r_shadow_selectedlight)
5958         {
5959                 Con_Print("No selected light.\n");
5960                 return;
5961         }
5962         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
5963 }
5964
5965 static void R_Shadow_EditLights_Lock_f(void)
5966 {
5967         if (!r_editlights.integer)
5968         {
5969                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
5970                 return;
5971         }
5972         if (r_editlights_lockcursor)
5973         {
5974                 r_editlights_lockcursor = false;
5975                 return;
5976         }
5977         if (!r_shadow_selectedlight)
5978         {
5979                 Con_Print("No selected light to lock on.\n");
5980                 return;
5981         }
5982         r_editlights_lockcursor = true;
5983 }
5984
5985 static void R_Shadow_EditLights_Init(void)
5986 {
5987         Cvar_RegisterVariable(&r_editlights);
5988         Cvar_RegisterVariable(&r_editlights_cursordistance);
5989         Cvar_RegisterVariable(&r_editlights_cursorpushback);
5990         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5991         Cvar_RegisterVariable(&r_editlights_cursorgrid);
5992         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5993         Cvar_RegisterVariable(&r_editlights_drawproperties);
5994         Cvar_RegisterVariable(&r_editlights_current_origin);
5995         Cvar_RegisterVariable(&r_editlights_current_angles);
5996         Cvar_RegisterVariable(&r_editlights_current_color);
5997         Cvar_RegisterVariable(&r_editlights_current_radius);
5998         Cvar_RegisterVariable(&r_editlights_current_corona);
5999         Cvar_RegisterVariable(&r_editlights_current_coronasize);
6000         Cvar_RegisterVariable(&r_editlights_current_style);
6001         Cvar_RegisterVariable(&r_editlights_current_shadows);
6002         Cvar_RegisterVariable(&r_editlights_current_cubemap);
6003         Cvar_RegisterVariable(&r_editlights_current_ambient);
6004         Cvar_RegisterVariable(&r_editlights_current_diffuse);
6005         Cvar_RegisterVariable(&r_editlights_current_specular);
6006         Cvar_RegisterVariable(&r_editlights_current_normalmode);
6007         Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6008         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6009         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6010         Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
6011         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6012         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6013         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6014         Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f, "changes a property on ALL lights at once (tip: use radiusscale and colorscale to alter these properties)");
6015         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6016         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6017         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6018         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6019         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6020         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6021         Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
6022         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6023 }
6024
6025
6026
6027 /*
6028 =============================================================================
6029
6030 LIGHT SAMPLING
6031
6032 =============================================================================
6033 */
6034
6035 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6036 {
6037         int i, numlights, flag, q;
6038         rtlight_t *light;
6039         dlight_t *dlight;
6040         float relativepoint[3];
6041         float color[3];
6042         float dist;
6043         float dist2;
6044         float intensity;
6045         float sa[3], sx[3], sy[3], sz[3], sd[3];
6046         float lightradius2;
6047
6048         // use first order spherical harmonics to combine directional lights
6049         for (q = 0; q < 3; q++)
6050                 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6051
6052         if (flags & LP_LIGHTMAP)
6053         {
6054                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6055                 {
6056                         float tempambient[3];
6057                         for (q = 0; q < 3; q++)
6058                                 tempambient[q] = color[q] = relativepoint[q] = 0;
6059                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6060                         // calculate a weighted average light direction as well
6061                         intensity = VectorLength(color);
6062                         for (q = 0; q < 3; q++)
6063                         {
6064                                 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6065                                 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6066                                 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6067                                 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6068                                 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6069                         }
6070                 }
6071                 else
6072                 {
6073                         // unlit map - fullbright but scaled by lightmapintensity
6074                         for (q = 0; q < 3; q++)
6075                                 sa[q] += lightmapintensity;
6076                 }
6077         }
6078
6079         if (flags & LP_RTWORLD)
6080         {
6081                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6082                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6083                 for (i = 0; i < numlights; i++)
6084                 {
6085                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6086                         if (!dlight)
6087                                 continue;
6088                         light = &dlight->rtlight;
6089                         if (!(light->flags & flag))
6090                                 continue;
6091                         // sample
6092                         lightradius2 = light->radius * light->radius;
6093                         VectorSubtract(light->shadoworigin, p, relativepoint);
6094                         dist2 = VectorLength2(relativepoint);
6095                         if (dist2 >= lightradius2)
6096                                 continue;
6097                         dist = sqrt(dist2) / light->radius;
6098                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6099                         if (intensity <= 0.0f)
6100                                 continue;
6101                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6102                                 continue;
6103                         for (q = 0; q < 3; q++)
6104                                 color[q] = light->currentcolor[q] * intensity;
6105                         intensity = VectorLength(color);
6106                         VectorNormalize(relativepoint);
6107                         for (q = 0; q < 3; q++)
6108                         {
6109                                 sa[q] += 0.5f * color[q];
6110                                 sx[q] += relativepoint[0] * color[q];
6111                                 sy[q] += relativepoint[1] * color[q];
6112                                 sz[q] += relativepoint[2] * color[q];
6113                                 sd[q] += intensity * relativepoint[q];
6114                         }
6115                 }
6116                 // FIXME: sample bouncegrid too!
6117         }
6118
6119         if (flags & LP_DYNLIGHT)
6120         {
6121                 // sample dlights
6122                 for (i = 0;i < r_refdef.scene.numlights;i++)
6123                 {
6124                         light = r_refdef.scene.lights[i];
6125                         // sample
6126                         lightradius2 = light->radius * light->radius;
6127                         VectorSubtract(light->shadoworigin, p, relativepoint);
6128                         dist2 = VectorLength2(relativepoint);
6129                         if (dist2 >= lightradius2)
6130                                 continue;
6131                         dist = sqrt(dist2) / light->radius;
6132                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6133                         if (intensity <= 0.0f)
6134                                 continue;
6135                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6136                                 continue;
6137                         for (q = 0; q < 3; q++)
6138                                 color[q] = light->currentcolor[q] * intensity;
6139                         intensity = VectorLength(color);
6140                         VectorNormalize(relativepoint);
6141                         for (q = 0; q < 3; q++)
6142                         {
6143                                 sa[q] += 0.5f * color[q];
6144                                 sx[q] += relativepoint[0] * color[q];
6145                                 sy[q] += relativepoint[1] * color[q];
6146                                 sz[q] += relativepoint[2] * color[q];
6147                                 sd[q] += intensity * relativepoint[q];
6148                         }
6149                 }
6150         }
6151
6152         // calculate the weighted-average light direction (bentnormal)
6153         for (q = 0; q < 3; q++)
6154                 lightdir[q] = sd[q];
6155         VectorNormalize(lightdir);
6156         for (q = 0; q < 3; q++)
6157         {
6158                 // extract the diffuse color along the chosen direction and scale it
6159                 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6160                 // subtract some of diffuse from ambient
6161                 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;
6162         }
6163 }