]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
Change shader permutation flags to 64bit.
[xonotic/darkplaces.git] / r_shadow.c
1
2 /*
3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
9
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
15
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
22
23 Patent warning:
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
29
30
31
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
38
39
40
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
46 in some ideal cases).
47
48
49
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however.  Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
60
61
62
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
69
70
71
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
80
81
82
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
89 texturing).
90
91
92
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
96
97
98
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
103
104
105
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light.  This technique is used heavily in many games (Doom3 does not support
114 this however).
115
116
117
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
127 other areas).
128
129
130
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
135 */
136
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
140 #include "portals.h"
141 #include "image.h"
142 #include "dpsoftrast.h"
143
144 #ifdef SUPPORTD3D
145 #include <d3d9.h>
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
147 #endif
148
149 static void R_Shadow_EditLights_Init(void);
150
151 typedef enum r_shadow_rendermode_e
152 {
153         R_SHADOW_RENDERMODE_NONE,
154         R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155         R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156         R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157         R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158         R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159         R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160         R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161         R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162         R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163         R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164         R_SHADOW_RENDERMODE_LIGHT_GLSL,
165         R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166         R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167         R_SHADOW_RENDERMODE_SHADOWMAP2D
168 }
169 r_shadow_rendermode_t;
170
171 typedef enum r_shadow_shadowmode_e
172 {
173         R_SHADOW_SHADOWMODE_STENCIL,
174         R_SHADOW_SHADOWMODE_SHADOWMAP2D
175 }
176 r_shadow_shadowmode_t;
177
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 int r_shadow_scenemaxlights;
183 int r_shadow_scenenumlights;
184 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
185 qboolean r_shadow_usingshadowmap2d;
186 qboolean r_shadow_usingshadowmaportho;
187 int r_shadow_shadowmapside;
188 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
189 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
190 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
191 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
192 #if 0
193 int r_shadow_drawbuffer;
194 int r_shadow_readbuffer;
195 #endif
196 int r_shadow_cullface_front, r_shadow_cullface_back;
197 GLuint r_shadow_fbo2d;
198 r_shadow_shadowmode_t r_shadow_shadowmode;
199 int r_shadow_shadowmapfilterquality;
200 int r_shadow_shadowmapdepthbits;
201 int r_shadow_shadowmapmaxsize;
202 int r_shadow_shadowmaptexturesize;
203 qboolean r_shadow_shadowmapvsdct;
204 qboolean r_shadow_shadowmapsampler;
205 qboolean r_shadow_shadowmapshadowsampler;
206 int r_shadow_shadowmappcf;
207 int r_shadow_shadowmapborder;
208 matrix4x4_t r_shadow_shadowmapmatrix;
209 int r_shadow_lightscissor[4];
210 qboolean r_shadow_usingdeferredprepass;
211 qboolean r_shadow_shadowmapdepthtexture;
212 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
213 int r_shadow_shadowmapatlas_modelshadows_x;
214 int r_shadow_shadowmapatlas_modelshadows_y;
215 int r_shadow_shadowmapatlas_modelshadows_size;
216 int maxshadowtriangles;
217 int *shadowelements;
218
219 int maxshadowvertices;
220 float *shadowvertex3f;
221
222 int maxshadowmark;
223 int numshadowmark;
224 int *shadowmark;
225 int *shadowmarklist;
226 int shadowmarkcount;
227
228 int maxshadowsides;
229 int numshadowsides;
230 unsigned char *shadowsides;
231 int *shadowsideslist;
232
233 int maxvertexupdate;
234 int *vertexupdate;
235 int *vertexremap;
236 int vertexupdatenum;
237
238 int r_shadow_buffer_numleafpvsbytes;
239 unsigned char *r_shadow_buffer_visitingleafpvs;
240 unsigned char *r_shadow_buffer_leafpvs;
241 int *r_shadow_buffer_leaflist;
242
243 int r_shadow_buffer_numsurfacepvsbytes;
244 unsigned char *r_shadow_buffer_surfacepvs;
245 int *r_shadow_buffer_surfacelist;
246 unsigned char *r_shadow_buffer_surfacesides;
247
248 int r_shadow_buffer_numshadowtrispvsbytes;
249 unsigned char *r_shadow_buffer_shadowtrispvs;
250 int r_shadow_buffer_numlighttrispvsbytes;
251 unsigned char *r_shadow_buffer_lighttrispvs;
252
253 rtexturepool_t *r_shadow_texturepool;
254 rtexture_t *r_shadow_attenuationgradienttexture;
255 rtexture_t *r_shadow_attenuation2dtexture;
256 rtexture_t *r_shadow_attenuation3dtexture;
257 skinframe_t *r_shadow_lightcorona;
258 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
259 rtexture_t *r_shadow_shadowmap2ddepthtexture;
260 rtexture_t *r_shadow_shadowmapvsdcttexture;
261
262 GLuint r_shadow_prepassgeometryfbo;
263 GLuint r_shadow_prepasslightingdiffusespecularfbo;
264 GLuint r_shadow_prepasslightingdiffusefbo;
265 int r_shadow_prepass_width;
266 int r_shadow_prepass_height;
267 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
268 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
269 rtexture_t *r_shadow_prepasslightingdiffusetexture;
270 rtexture_t *r_shadow_prepasslightingspeculartexture;
271
272 // keep track of the provided framebuffer info
273 static int r_shadow_fb_fbo;
274 static rtexture_t *r_shadow_fb_depthtexture;
275 static rtexture_t *r_shadow_fb_colortexture;
276
277 // lights are reloaded when this changes
278 char r_shadow_mapname[MAX_QPATH];
279
280 // buffer for doing corona fading
281 unsigned int r_shadow_occlusion_buf = 0;
282
283 // used only for light filters (cubemaps)
284 rtexturepool_t *r_shadow_filters_texturepool;
285
286 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"};
287 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"};
288 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
289 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"};
290 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)"};
291 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
292 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)"};
293 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"};
294 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
295 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
296 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
297 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
298 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
299 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
300 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
301 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
302 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
303 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)"};
304 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
305 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
306 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
307 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
308 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)"};
309 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)"};
310 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"};
311 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
312 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
313 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"};
314 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)"};
315 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
316 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)"};
317 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes"};
318 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)"};
319 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
320 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
321 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
322 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"};
323 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..."};
324 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"};
325 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"};
326 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
327 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
328 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
329 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
330 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
331 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
332 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
333 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
334 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
335 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
336 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
337 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"};
338 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"};
339 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
340 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0.1", "make light bounds bigger by *1.0+enlarge"};
341 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)"};
342 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)"};
343 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"};
344 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)"};
345 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"};
346 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"};
347 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" };
348 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)"};
349 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
350 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"};
351 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
352 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
353 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
354 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"};
355 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)"};
356 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
357 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"};
358 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
359 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
360 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
361 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"};
362 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)"};
363 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
364 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"};
365 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"};
366 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)" };
367 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"};
368 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
369 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" };
370 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)" };
371 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"};
372 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
373 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" };
374 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
375 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
376 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"};
377 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
378 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)" };
379 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
380 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
381 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"};
382 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility) - bad performance (synchronous rendering) - worse on multi-gpu!"};
383 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
384 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
385 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
386 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
387 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
388 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
389 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
390 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
391 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
392 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
393 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
394 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
395 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
396 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
397 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
398 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
399 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
400 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
401 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
402 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
403 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
404 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
405 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
406 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
407
408 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
409
410 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
411 #define ATTENTABLESIZE 256
412 // 1D gradient, 2D circle and 3D sphere attenuation textures
413 #define ATTEN1DSIZE 32
414 #define ATTEN2DSIZE 64
415 #define ATTEN3DSIZE 32
416
417 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
418 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
419 static float r_shadow_attentable[ATTENTABLESIZE+1];
420
421 rtlight_t *r_shadow_compilingrtlight;
422 static memexpandablearray_t r_shadow_worldlightsarray;
423 dlight_t *r_shadow_selectedlight;
424 dlight_t r_shadow_bufferlight;
425 vec3_t r_editlights_cursorlocation;
426 qboolean r_editlights_lockcursor;
427
428 extern int con_vislines;
429
430 void R_Shadow_UncompileWorldLights(void);
431 void R_Shadow_ClearWorldLights(void);
432 void R_Shadow_SaveWorldLights(void);
433 void R_Shadow_LoadWorldLights(void);
434 void R_Shadow_LoadLightsFile(void);
435 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
436 void R_Shadow_EditLights_Reload_f(void);
437 void R_Shadow_ValidateCvars(void);
438 static void R_Shadow_MakeTextures(void);
439
440 #define EDLIGHTSPRSIZE                  8
441 skinframe_t *r_editlights_sprcursor;
442 skinframe_t *r_editlights_sprlight;
443 skinframe_t *r_editlights_sprnoshadowlight;
444 skinframe_t *r_editlights_sprcubemaplight;
445 skinframe_t *r_editlights_sprcubemapnoshadowlight;
446 skinframe_t *r_editlights_sprselection;
447
448 static void R_Shadow_DrawModelShadowMaps(void);
449 static void R_Shadow_MakeShadowMap(int texturesize);
450 static void R_Shadow_MakeVSDCT(void);
451 static void R_Shadow_SetShadowMode(void)
452 {
453         r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
454         r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
455         r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
456         r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
457         r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
458         r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
459         r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
460         r_shadow_shadowmapsampler = false;
461         r_shadow_shadowmappcf = 0;
462         r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
463         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
464         Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
465         if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
466         {
467                 switch(vid.renderpath)
468                 {
469                 case RENDERPATH_GL20:
470                         if(r_shadow_shadowmapfilterquality < 0)
471                         {
472                                 if (!r_fb.usedepthtextures)
473                                         r_shadow_shadowmappcf = 1;
474                                 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
475                                 {
476                                         r_shadow_shadowmapsampler = true;
477                                         r_shadow_shadowmappcf = 1;
478                                 }
479                                 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
480                                         r_shadow_shadowmappcf = 1;
481                                 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
482                                         r_shadow_shadowmappcf = 1;
483                                 else
484                                         r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
485                         }
486                         else
487                         {
488                 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
489                                 switch (r_shadow_shadowmapfilterquality)
490                                 {
491                                 case 1:
492                                         break;
493                                 case 2:
494                                         r_shadow_shadowmappcf = 1;
495                                         break;
496                                 case 3:
497                                         r_shadow_shadowmappcf = 1;
498                                         break;
499                                 case 4:
500                                         r_shadow_shadowmappcf = 2;
501                                         break;
502                                 }
503                         }
504                         if (!r_fb.usedepthtextures)
505                                 r_shadow_shadowmapsampler = false;
506                         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
507                         break;
508                 case RENDERPATH_D3D9:
509                 case RENDERPATH_D3D10:
510                 case RENDERPATH_D3D11:
511                 case RENDERPATH_SOFT:
512                         r_shadow_shadowmapsampler = false;
513                         r_shadow_shadowmappcf = 1;
514                         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
515                         break;
516                 case RENDERPATH_GL11:
517                 case RENDERPATH_GL13:
518                 case RENDERPATH_GLES1:
519                 case RENDERPATH_GLES2:
520                         break;
521                 }
522         }
523
524         if(R_CompileShader_CheckStaticParms())
525                 R_GLSL_Restart_f();
526 }
527
528 qboolean R_Shadow_ShadowMappingEnabled(void)
529 {
530         switch (r_shadow_shadowmode)
531         {
532         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
533                 return true;
534         default:
535                 return false;
536         }
537 }
538
539 static void R_Shadow_FreeShadowMaps(void)
540 {
541         Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
542
543         R_Shadow_SetShadowMode();
544
545         R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
546
547         r_shadow_fbo2d = 0;
548
549         if (r_shadow_shadowmap2ddepthtexture)
550                 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
551         r_shadow_shadowmap2ddepthtexture = NULL;
552
553         if (r_shadow_shadowmap2ddepthbuffer)
554                 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
555         r_shadow_shadowmap2ddepthbuffer = NULL;
556
557         if (r_shadow_shadowmapvsdcttexture)
558                 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
559         r_shadow_shadowmapvsdcttexture = NULL;
560 }
561
562 static void r_shadow_start(void)
563 {
564         // allocate vertex processing arrays
565         memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
566         r_shadow_attenuationgradienttexture = NULL;
567         r_shadow_attenuation2dtexture = NULL;
568         r_shadow_attenuation3dtexture = NULL;
569         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
570         r_shadow_shadowmap2ddepthtexture = NULL;
571         r_shadow_shadowmap2ddepthbuffer = NULL;
572         r_shadow_shadowmapvsdcttexture = NULL;
573         r_shadow_shadowmapmaxsize = 0;
574         r_shadow_shadowmaptexturesize = 0;
575         r_shadow_shadowmapfilterquality = -1;
576         r_shadow_shadowmapdepthbits = 0;
577         r_shadow_shadowmapvsdct = false;
578         r_shadow_shadowmapsampler = false;
579         r_shadow_shadowmappcf = 0;
580         r_shadow_fbo2d = 0;
581
582         R_Shadow_FreeShadowMaps();
583
584         r_shadow_texturepool = NULL;
585         r_shadow_filters_texturepool = NULL;
586         R_Shadow_ValidateCvars();
587         R_Shadow_MakeTextures();
588         r_shadow_scenemaxlights = 0;
589         r_shadow_scenenumlights = 0;
590         r_shadow_scenelightlist = NULL;
591         maxshadowtriangles = 0;
592         shadowelements = NULL;
593         maxshadowvertices = 0;
594         shadowvertex3f = NULL;
595         maxvertexupdate = 0;
596         vertexupdate = NULL;
597         vertexremap = NULL;
598         vertexupdatenum = 0;
599         maxshadowmark = 0;
600         numshadowmark = 0;
601         shadowmark = NULL;
602         shadowmarklist = NULL;
603         shadowmarkcount = 0;
604         maxshadowsides = 0;
605         numshadowsides = 0;
606         shadowsides = NULL;
607         shadowsideslist = NULL;
608         r_shadow_buffer_numleafpvsbytes = 0;
609         r_shadow_buffer_visitingleafpvs = NULL;
610         r_shadow_buffer_leafpvs = NULL;
611         r_shadow_buffer_leaflist = NULL;
612         r_shadow_buffer_numsurfacepvsbytes = 0;
613         r_shadow_buffer_surfacepvs = NULL;
614         r_shadow_buffer_surfacelist = NULL;
615         r_shadow_buffer_surfacesides = NULL;
616         r_shadow_buffer_numshadowtrispvsbytes = 0;
617         r_shadow_buffer_shadowtrispvs = NULL;
618         r_shadow_buffer_numlighttrispvsbytes = 0;
619         r_shadow_buffer_lighttrispvs = NULL;
620
621         r_shadow_usingdeferredprepass = false;
622         r_shadow_prepass_width = r_shadow_prepass_height = 0;
623
624         // determine renderpath specific capabilities, we don't need to figure
625         // these out per frame...
626         switch(vid.renderpath)
627         {
628         case RENDERPATH_GL20:
629                 r_shadow_bouncegrid_state.allowdirectionalshading = true;
630                 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
631                 break;
632         case RENDERPATH_GLES2:
633                 // for performance reasons, do not use directional shading on GLES devices
634                 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
635                 break;
636                 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
637         case RENDERPATH_GL11:
638         case RENDERPATH_GL13:
639         case RENDERPATH_GLES1:
640         case RENDERPATH_SOFT:
641         case RENDERPATH_D3D9:
642         case RENDERPATH_D3D10:
643         case RENDERPATH_D3D11:
644                 break;
645         }
646 }
647
648 static void R_Shadow_FreeDeferred(void);
649 static void r_shadow_shutdown(void)
650 {
651         CHECKGLERROR
652         R_Shadow_UncompileWorldLights();
653
654         R_Shadow_FreeShadowMaps();
655
656         r_shadow_usingdeferredprepass = false;
657         if (r_shadow_prepass_width)
658                 R_Shadow_FreeDeferred();
659         r_shadow_prepass_width = r_shadow_prepass_height = 0;
660
661         CHECKGLERROR
662         r_shadow_scenemaxlights = 0;
663         r_shadow_scenenumlights = 0;
664         if (r_shadow_scenelightlist)
665                 Mem_Free(r_shadow_scenelightlist);
666         r_shadow_scenelightlist = NULL;
667         r_shadow_bouncegrid_state.highpixels = NULL;
668         if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
669         if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
670         if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
671         if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
672         if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
673         r_shadow_bouncegrid_state.maxsplatpaths = 0;
674         memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
675         r_shadow_attenuationgradienttexture = NULL;
676         r_shadow_attenuation2dtexture = NULL;
677         r_shadow_attenuation3dtexture = NULL;
678         R_FreeTexturePool(&r_shadow_texturepool);
679         R_FreeTexturePool(&r_shadow_filters_texturepool);
680         maxshadowtriangles = 0;
681         if (shadowelements)
682                 Mem_Free(shadowelements);
683         shadowelements = NULL;
684         if (shadowvertex3f)
685                 Mem_Free(shadowvertex3f);
686         shadowvertex3f = NULL;
687         maxvertexupdate = 0;
688         if (vertexupdate)
689                 Mem_Free(vertexupdate);
690         vertexupdate = NULL;
691         if (vertexremap)
692                 Mem_Free(vertexremap);
693         vertexremap = NULL;
694         vertexupdatenum = 0;
695         maxshadowmark = 0;
696         numshadowmark = 0;
697         if (shadowmark)
698                 Mem_Free(shadowmark);
699         shadowmark = NULL;
700         if (shadowmarklist)
701                 Mem_Free(shadowmarklist);
702         shadowmarklist = NULL;
703         shadowmarkcount = 0;
704         maxshadowsides = 0;
705         numshadowsides = 0;
706         if (shadowsides)
707                 Mem_Free(shadowsides);
708         shadowsides = NULL;
709         if (shadowsideslist)
710                 Mem_Free(shadowsideslist);
711         shadowsideslist = NULL;
712         r_shadow_buffer_numleafpvsbytes = 0;
713         if (r_shadow_buffer_visitingleafpvs)
714                 Mem_Free(r_shadow_buffer_visitingleafpvs);
715         r_shadow_buffer_visitingleafpvs = NULL;
716         if (r_shadow_buffer_leafpvs)
717                 Mem_Free(r_shadow_buffer_leafpvs);
718         r_shadow_buffer_leafpvs = NULL;
719         if (r_shadow_buffer_leaflist)
720                 Mem_Free(r_shadow_buffer_leaflist);
721         r_shadow_buffer_leaflist = NULL;
722         r_shadow_buffer_numsurfacepvsbytes = 0;
723         if (r_shadow_buffer_surfacepvs)
724                 Mem_Free(r_shadow_buffer_surfacepvs);
725         r_shadow_buffer_surfacepvs = NULL;
726         if (r_shadow_buffer_surfacelist)
727                 Mem_Free(r_shadow_buffer_surfacelist);
728         r_shadow_buffer_surfacelist = NULL;
729         if (r_shadow_buffer_surfacesides)
730                 Mem_Free(r_shadow_buffer_surfacesides);
731         r_shadow_buffer_surfacesides = NULL;
732         r_shadow_buffer_numshadowtrispvsbytes = 0;
733         if (r_shadow_buffer_shadowtrispvs)
734                 Mem_Free(r_shadow_buffer_shadowtrispvs);
735         r_shadow_buffer_numlighttrispvsbytes = 0;
736         if (r_shadow_buffer_lighttrispvs)
737                 Mem_Free(r_shadow_buffer_lighttrispvs);
738 }
739
740 static void r_shadow_newmap(void)
741 {
742         r_shadow_bouncegrid_state.highpixels = NULL;
743         if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
744         if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
745         if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
746         if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
747         if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
748         r_shadow_bouncegrid_state.maxsplatpaths = 0;
749         if (r_shadow_bouncegrid_state.texture)    R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
750         if (r_shadow_lightcorona)                 R_SkinFrame_MarkUsed(r_shadow_lightcorona);
751         if (r_editlights_sprcursor)               R_SkinFrame_MarkUsed(r_editlights_sprcursor);
752         if (r_editlights_sprlight)                R_SkinFrame_MarkUsed(r_editlights_sprlight);
753         if (r_editlights_sprnoshadowlight)        R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
754         if (r_editlights_sprcubemaplight)         R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
755         if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
756         if (r_editlights_sprselection)            R_SkinFrame_MarkUsed(r_editlights_sprselection);
757         if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
758                 R_Shadow_EditLights_Reload_f();
759 }
760
761 void R_Shadow_Init(void)
762 {
763         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
764         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
765         Cvar_RegisterVariable(&r_shadow_usebihculling);
766         Cvar_RegisterVariable(&r_shadow_usenormalmap);
767         Cvar_RegisterVariable(&r_shadow_debuglight);
768         Cvar_RegisterVariable(&r_shadow_deferred);
769         Cvar_RegisterVariable(&r_shadow_gloss);
770         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
771         Cvar_RegisterVariable(&r_shadow_glossintensity);
772         Cvar_RegisterVariable(&r_shadow_glossexponent);
773         Cvar_RegisterVariable(&r_shadow_gloss2exponent);
774         Cvar_RegisterVariable(&r_shadow_glossexact);
775         Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
776         Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
777         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
778         Cvar_RegisterVariable(&r_shadow_lightradiusscale);
779         Cvar_RegisterVariable(&r_shadow_projectdistance);
780         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
781         Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
782         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
783         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
784         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
785         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
786         Cvar_RegisterVariable(&r_shadow_realtime_world);
787         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
788         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
789         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
790         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
791         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
792         Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
793         Cvar_RegisterVariable(&r_shadow_scissor);
794         Cvar_RegisterVariable(&r_shadow_shadowmapping);
795         Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
796         Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
797         Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
798         Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
799         Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
800         Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
801         Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
802         Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
803 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
804 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
805         Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
806         Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
807         Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
808         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
809         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
810         Cvar_RegisterVariable(&r_shadow_sortsurfaces);
811         Cvar_RegisterVariable(&r_shadow_polygonfactor);
812         Cvar_RegisterVariable(&r_shadow_polygonoffset);
813         Cvar_RegisterVariable(&r_shadow_texture3d);
814         Cvar_RegisterVariable(&r_shadow_culllights_pvs);
815         Cvar_RegisterVariable(&r_shadow_culllights_trace);
816         Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
817         Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
818         Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
819         Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
820         Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
821         Cvar_RegisterVariable(&r_shadow_bouncegrid);
822         Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
823         Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
824         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
825         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
826         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
827         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
828         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
829         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
830         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
831         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
832         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
833         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
834         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
835         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
836         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
837         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
838         Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
839         Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
840         Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
841         Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
842         Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
843         Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
844         Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
845         Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
846         Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
847         Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
848         Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
849         Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
850         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
851         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
852         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
853         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
854         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
855         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
856         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
857         Cvar_RegisterVariable(&r_coronas);
858         Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
859         Cvar_RegisterVariable(&r_coronas_occlusionquery);
860         Cvar_RegisterVariable(&gl_flashblend);
861         Cvar_RegisterVariable(&gl_ext_separatestencil);
862         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
863         R_Shadow_EditLights_Init();
864         Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
865         r_shadow_scenemaxlights = 0;
866         r_shadow_scenenumlights = 0;
867         r_shadow_scenelightlist = NULL;
868         maxshadowtriangles = 0;
869         shadowelements = NULL;
870         maxshadowvertices = 0;
871         shadowvertex3f = NULL;
872         maxvertexupdate = 0;
873         vertexupdate = NULL;
874         vertexremap = NULL;
875         vertexupdatenum = 0;
876         maxshadowmark = 0;
877         numshadowmark = 0;
878         shadowmark = NULL;
879         shadowmarklist = NULL;
880         shadowmarkcount = 0;
881         maxshadowsides = 0;
882         numshadowsides = 0;
883         shadowsides = NULL;
884         shadowsideslist = NULL;
885         r_shadow_buffer_numleafpvsbytes = 0;
886         r_shadow_buffer_visitingleafpvs = NULL;
887         r_shadow_buffer_leafpvs = NULL;
888         r_shadow_buffer_leaflist = NULL;
889         r_shadow_buffer_numsurfacepvsbytes = 0;
890         r_shadow_buffer_surfacepvs = NULL;
891         r_shadow_buffer_surfacelist = NULL;
892         r_shadow_buffer_surfacesides = NULL;
893         r_shadow_buffer_shadowtrispvs = NULL;
894         r_shadow_buffer_lighttrispvs = NULL;
895         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
896 }
897
898 matrix4x4_t matrix_attenuationxyz =
899 {
900         {
901                 {0.5, 0.0, 0.0, 0.5},
902                 {0.0, 0.5, 0.0, 0.5},
903                 {0.0, 0.0, 0.5, 0.5},
904                 {0.0, 0.0, 0.0, 1.0}
905         }
906 };
907
908 matrix4x4_t matrix_attenuationz =
909 {
910         {
911                 {0.0, 0.0, 0.5, 0.5},
912                 {0.0, 0.0, 0.0, 0.5},
913                 {0.0, 0.0, 0.0, 0.5},
914                 {0.0, 0.0, 0.0, 1.0}
915         }
916 };
917
918 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
919 {
920         numvertices = ((numvertices + 255) & ~255) * vertscale;
921         numtriangles = ((numtriangles + 255) & ~255) * triscale;
922         // make sure shadowelements is big enough for this volume
923         if (maxshadowtriangles < numtriangles)
924         {
925                 maxshadowtriangles = numtriangles;
926                 if (shadowelements)
927                         Mem_Free(shadowelements);
928                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
929         }
930         // make sure shadowvertex3f is big enough for this volume
931         if (maxshadowvertices < numvertices)
932         {
933                 maxshadowvertices = numvertices;
934                 if (shadowvertex3f)
935                         Mem_Free(shadowvertex3f);
936                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
937         }
938 }
939
940 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
941 {
942         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
943         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
944         int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
945         int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
946         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
947         {
948                 if (r_shadow_buffer_visitingleafpvs)
949                         Mem_Free(r_shadow_buffer_visitingleafpvs);
950                 if (r_shadow_buffer_leafpvs)
951                         Mem_Free(r_shadow_buffer_leafpvs);
952                 if (r_shadow_buffer_leaflist)
953                         Mem_Free(r_shadow_buffer_leaflist);
954                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
955                 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
956                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
957                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
958         }
959         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
960         {
961                 if (r_shadow_buffer_surfacepvs)
962                         Mem_Free(r_shadow_buffer_surfacepvs);
963                 if (r_shadow_buffer_surfacelist)
964                         Mem_Free(r_shadow_buffer_surfacelist);
965                 if (r_shadow_buffer_surfacesides)
966                         Mem_Free(r_shadow_buffer_surfacesides);
967                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
968                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
969                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
970                 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
971         }
972         if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
973         {
974                 if (r_shadow_buffer_shadowtrispvs)
975                         Mem_Free(r_shadow_buffer_shadowtrispvs);
976                 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
977                 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
978         }
979         if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
980         {
981                 if (r_shadow_buffer_lighttrispvs)
982                         Mem_Free(r_shadow_buffer_lighttrispvs);
983                 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
984                 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
985         }
986 }
987
988 void R_Shadow_PrepareShadowMark(int numtris)
989 {
990         // make sure shadowmark is big enough for this volume
991         if (maxshadowmark < numtris)
992         {
993                 maxshadowmark = numtris;
994                 if (shadowmark)
995                         Mem_Free(shadowmark);
996                 if (shadowmarklist)
997                         Mem_Free(shadowmarklist);
998                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
999                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
1000                 shadowmarkcount = 0;
1001         }
1002         shadowmarkcount++;
1003         // if shadowmarkcount wrapped we clear the array and adjust accordingly
1004         if (shadowmarkcount == 0)
1005         {
1006                 shadowmarkcount = 1;
1007                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
1008         }
1009         numshadowmark = 0;
1010 }
1011
1012 void R_Shadow_PrepareShadowSides(int numtris)
1013 {
1014         if (maxshadowsides < numtris)
1015         {
1016                 maxshadowsides = numtris;
1017                 if (shadowsides)
1018                         Mem_Free(shadowsides);
1019                 if (shadowsideslist)
1020                         Mem_Free(shadowsideslist);
1021                 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1022                 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1023         }
1024         numshadowsides = 0;
1025 }
1026
1027 static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
1028 {
1029         int i, j;
1030         int outtriangles = 0, outvertices = 0;
1031         const int *element;
1032         const float *vertex;
1033         float ratio, direction[3], projectvector[3];
1034
1035         if (projectdirection)
1036                 VectorScale(projectdirection, projectdistance, projectvector);
1037         else
1038                 VectorClear(projectvector);
1039
1040         // create the vertices
1041         if (projectdirection)
1042         {
1043                 for (i = 0;i < numshadowmarktris;i++)
1044                 {
1045                         element = inelement3i + shadowmarktris[i] * 3;
1046                         for (j = 0;j < 3;j++)
1047                         {
1048                                 if (vertexupdate[element[j]] != vertexupdatenum)
1049                                 {
1050                                         vertexupdate[element[j]] = vertexupdatenum;
1051                                         vertexremap[element[j]] = outvertices;
1052                                         vertex = invertex3f + element[j] * 3;
1053                                         // project one copy of the vertex according to projectvector
1054                                         VectorCopy(vertex, outvertex3f);
1055                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
1056                                         outvertex3f += 6;
1057                                         outvertices += 2;
1058                                 }
1059                         }
1060                 }
1061         }
1062         else
1063         {
1064                 for (i = 0;i < numshadowmarktris;i++)
1065                 {
1066                         element = inelement3i + shadowmarktris[i] * 3;
1067                         for (j = 0;j < 3;j++)
1068                         {
1069                                 if (vertexupdate[element[j]] != vertexupdatenum)
1070                                 {
1071                                         vertexupdate[element[j]] = vertexupdatenum;
1072                                         vertexremap[element[j]] = outvertices;
1073                                         vertex = invertex3f + element[j] * 3;
1074                                         // project one copy of the vertex to the sphere radius of the light
1075                                         // (FIXME: would projecting it to the light box be better?)
1076                                         VectorSubtract(vertex, projectorigin, direction);
1077                                         ratio = projectdistance / VectorLength(direction);
1078                                         VectorCopy(vertex, outvertex3f);
1079                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1080                                         outvertex3f += 6;
1081                                         outvertices += 2;
1082                                 }
1083                         }
1084                 }
1085         }
1086
1087         if (r_shadow_frontsidecasting.integer)
1088         {
1089                 for (i = 0;i < numshadowmarktris;i++)
1090                 {
1091                         int remappedelement[3];
1092                         int markindex;
1093                         const int *neighbortriangle;
1094
1095                         markindex = shadowmarktris[i] * 3;
1096                         element = inelement3i + markindex;
1097                         neighbortriangle = inneighbor3i + markindex;
1098                         // output the front and back triangles
1099                         outelement3i[0] = vertexremap[element[0]];
1100                         outelement3i[1] = vertexremap[element[1]];
1101                         outelement3i[2] = vertexremap[element[2]];
1102                         outelement3i[3] = vertexremap[element[2]] + 1;
1103                         outelement3i[4] = vertexremap[element[1]] + 1;
1104                         outelement3i[5] = vertexremap[element[0]] + 1;
1105
1106                         outelement3i += 6;
1107                         outtriangles += 2;
1108                         // output the sides (facing outward from this triangle)
1109                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1110                         {
1111                                 remappedelement[0] = vertexremap[element[0]];
1112                                 remappedelement[1] = vertexremap[element[1]];
1113                                 outelement3i[0] = remappedelement[1];
1114                                 outelement3i[1] = remappedelement[0];
1115                                 outelement3i[2] = remappedelement[0] + 1;
1116                                 outelement3i[3] = remappedelement[1];
1117                                 outelement3i[4] = remappedelement[0] + 1;
1118                                 outelement3i[5] = remappedelement[1] + 1;
1119
1120                                 outelement3i += 6;
1121                                 outtriangles += 2;
1122                         }
1123                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1124                         {
1125                                 remappedelement[1] = vertexremap[element[1]];
1126                                 remappedelement[2] = vertexremap[element[2]];
1127                                 outelement3i[0] = remappedelement[2];
1128                                 outelement3i[1] = remappedelement[1];
1129                                 outelement3i[2] = remappedelement[1] + 1;
1130                                 outelement3i[3] = remappedelement[2];
1131                                 outelement3i[4] = remappedelement[1] + 1;
1132                                 outelement3i[5] = remappedelement[2] + 1;
1133
1134                                 outelement3i += 6;
1135                                 outtriangles += 2;
1136                         }
1137                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1138                         {
1139                                 remappedelement[0] = vertexremap[element[0]];
1140                                 remappedelement[2] = vertexremap[element[2]];
1141                                 outelement3i[0] = remappedelement[0];
1142                                 outelement3i[1] = remappedelement[2];
1143                                 outelement3i[2] = remappedelement[2] + 1;
1144                                 outelement3i[3] = remappedelement[0];
1145                                 outelement3i[4] = remappedelement[2] + 1;
1146                                 outelement3i[5] = remappedelement[0] + 1;
1147
1148                                 outelement3i += 6;
1149                                 outtriangles += 2;
1150                         }
1151                 }
1152         }
1153         else
1154         {
1155                 for (i = 0;i < numshadowmarktris;i++)
1156                 {
1157                         int remappedelement[3];
1158                         int markindex;
1159                         const int *neighbortriangle;
1160
1161                         markindex = shadowmarktris[i] * 3;
1162                         element = inelement3i + markindex;
1163                         neighbortriangle = inneighbor3i + markindex;
1164                         // output the front and back triangles
1165                         outelement3i[0] = vertexremap[element[2]];
1166                         outelement3i[1] = vertexremap[element[1]];
1167                         outelement3i[2] = vertexremap[element[0]];
1168                         outelement3i[3] = vertexremap[element[0]] + 1;
1169                         outelement3i[4] = vertexremap[element[1]] + 1;
1170                         outelement3i[5] = vertexremap[element[2]] + 1;
1171
1172                         outelement3i += 6;
1173                         outtriangles += 2;
1174                         // output the sides (facing outward from this triangle)
1175                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1176                         {
1177                                 remappedelement[0] = vertexremap[element[0]];
1178                                 remappedelement[1] = vertexremap[element[1]];
1179                                 outelement3i[0] = remappedelement[0];
1180                                 outelement3i[1] = remappedelement[1];
1181                                 outelement3i[2] = remappedelement[1] + 1;
1182                                 outelement3i[3] = remappedelement[0];
1183                                 outelement3i[4] = remappedelement[1] + 1;
1184                                 outelement3i[5] = remappedelement[0] + 1;
1185
1186                                 outelement3i += 6;
1187                                 outtriangles += 2;
1188                         }
1189                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1190                         {
1191                                 remappedelement[1] = vertexremap[element[1]];
1192                                 remappedelement[2] = vertexremap[element[2]];
1193                                 outelement3i[0] = remappedelement[1];
1194                                 outelement3i[1] = remappedelement[2];
1195                                 outelement3i[2] = remappedelement[2] + 1;
1196                                 outelement3i[3] = remappedelement[1];
1197                                 outelement3i[4] = remappedelement[2] + 1;
1198                                 outelement3i[5] = remappedelement[1] + 1;
1199
1200                                 outelement3i += 6;
1201                                 outtriangles += 2;
1202                         }
1203                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1204                         {
1205                                 remappedelement[0] = vertexremap[element[0]];
1206                                 remappedelement[2] = vertexremap[element[2]];
1207                                 outelement3i[0] = remappedelement[2];
1208                                 outelement3i[1] = remappedelement[0];
1209                                 outelement3i[2] = remappedelement[0] + 1;
1210                                 outelement3i[3] = remappedelement[2];
1211                                 outelement3i[4] = remappedelement[0] + 1;
1212                                 outelement3i[5] = remappedelement[2] + 1;
1213
1214                                 outelement3i += 6;
1215                                 outtriangles += 2;
1216                         }
1217                 }
1218         }
1219         if (outnumvertices)
1220                 *outnumvertices = outvertices;
1221         return outtriangles;
1222 }
1223
1224 static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
1225 {
1226         int i, j, k;
1227         int outtriangles = 0, outvertices = 0;
1228         const int *element;
1229         const float *vertex;
1230         float ratio, direction[3], projectvector[3];
1231         qboolean side[4];
1232
1233         if (projectdirection)
1234                 VectorScale(projectdirection, projectdistance, projectvector);
1235         else
1236                 VectorClear(projectvector);
1237
1238         for (i = 0;i < numshadowmarktris;i++)
1239         {
1240                 int remappedelement[3];
1241                 int markindex;
1242                 const int *neighbortriangle;
1243
1244                 markindex = shadowmarktris[i] * 3;
1245                 neighbortriangle = inneighbor3i + markindex;
1246                 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1247                 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1248                 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1249                 if (side[0] + side[1] + side[2] == 0)
1250                         continue;
1251
1252                 side[3] = side[0];
1253                 element = inelement3i + markindex;
1254
1255                 // create the vertices
1256                 for (j = 0;j < 3;j++)
1257                 {
1258                         if (side[j] + side[j+1] == 0)
1259                                 continue;
1260                         k = element[j];
1261                         if (vertexupdate[k] != vertexupdatenum)
1262                         {
1263                                 vertexupdate[k] = vertexupdatenum;
1264                                 vertexremap[k] = outvertices;
1265                                 vertex = invertex3f + k * 3;
1266                                 VectorCopy(vertex, outvertex3f);
1267                                 if (projectdirection)
1268                                 {
1269                                         // project one copy of the vertex according to projectvector
1270                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
1271                                 }
1272                                 else
1273                                 {
1274                                         // project one copy of the vertex to the sphere radius of the light
1275                                         // (FIXME: would projecting it to the light box be better?)
1276                                         VectorSubtract(vertex, projectorigin, direction);
1277                                         ratio = projectdistance / VectorLength(direction);
1278                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1279                                 }
1280                                 outvertex3f += 6;
1281                                 outvertices += 2;
1282                         }
1283                 }
1284
1285                 // output the sides (facing outward from this triangle)
1286                 if (!side[0])
1287                 {
1288                         remappedelement[0] = vertexremap[element[0]];
1289                         remappedelement[1] = vertexremap[element[1]];
1290                         outelement3i[0] = remappedelement[1];
1291                         outelement3i[1] = remappedelement[0];
1292                         outelement3i[2] = remappedelement[0] + 1;
1293                         outelement3i[3] = remappedelement[1];
1294                         outelement3i[4] = remappedelement[0] + 1;
1295                         outelement3i[5] = remappedelement[1] + 1;
1296
1297                         outelement3i += 6;
1298                         outtriangles += 2;
1299                 }
1300                 if (!side[1])
1301                 {
1302                         remappedelement[1] = vertexremap[element[1]];
1303                         remappedelement[2] = vertexremap[element[2]];
1304                         outelement3i[0] = remappedelement[2];
1305                         outelement3i[1] = remappedelement[1];
1306                         outelement3i[2] = remappedelement[1] + 1;
1307                         outelement3i[3] = remappedelement[2];
1308                         outelement3i[4] = remappedelement[1] + 1;
1309                         outelement3i[5] = remappedelement[2] + 1;
1310
1311                         outelement3i += 6;
1312                         outtriangles += 2;
1313                 }
1314                 if (!side[2])
1315                 {
1316                         remappedelement[0] = vertexremap[element[0]];
1317                         remappedelement[2] = vertexremap[element[2]];
1318                         outelement3i[0] = remappedelement[0];
1319                         outelement3i[1] = remappedelement[2];
1320                         outelement3i[2] = remappedelement[2] + 1;
1321                         outelement3i[3] = remappedelement[0];
1322                         outelement3i[4] = remappedelement[2] + 1;
1323                         outelement3i[5] = remappedelement[0] + 1;
1324
1325                         outelement3i += 6;
1326                         outtriangles += 2;
1327                 }
1328         }
1329         if (outnumvertices)
1330                 *outnumvertices = outvertices;
1331         return outtriangles;
1332 }
1333
1334 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
1335 {
1336         int t, tend;
1337         const int *e;
1338         const float *v[3];
1339         float normal[3];
1340         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1341                 return;
1342         tend = firsttriangle + numtris;
1343         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1344         {
1345                 // surface box entirely inside light box, no box cull
1346                 if (projectdirection)
1347                 {
1348                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1349                         {
1350                                 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1351                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1352                                         shadowmarklist[numshadowmark++] = t;
1353                         }
1354                 }
1355                 else
1356                 {
1357                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1358                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1359                                         shadowmarklist[numshadowmark++] = t;
1360                 }
1361         }
1362         else
1363         {
1364                 // surface box not entirely inside light box, cull each triangle
1365                 if (projectdirection)
1366                 {
1367                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1368                         {
1369                                 v[0] = invertex3f + e[0] * 3;
1370                                 v[1] = invertex3f + e[1] * 3;
1371                                 v[2] = invertex3f + e[2] * 3;
1372                                 TriangleNormal(v[0], v[1], v[2], normal);
1373                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1374                                  && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1375                                         shadowmarklist[numshadowmark++] = t;
1376                         }
1377                 }
1378                 else
1379                 {
1380                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1381                         {
1382                                 v[0] = invertex3f + e[0] * 3;
1383                                 v[1] = invertex3f + e[1] * 3;
1384                                 v[2] = invertex3f + e[2] * 3;
1385                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1386                                  && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1387                                         shadowmarklist[numshadowmark++] = t;
1388                         }
1389                 }
1390         }
1391 }
1392
1393 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1394 {
1395 #if 1
1396         return false;
1397 #else
1398         if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1399                 return false;
1400         // check if the shadow volume intersects the near plane
1401         //
1402         // a ray between the eye and light origin may intersect the caster,
1403         // indicating that the shadow may touch the eye location, however we must
1404         // test the near plane (a polygon), not merely the eye location, so it is
1405         // easiest to enlarge the caster bounding shape slightly for this.
1406         // TODO
1407         return true;
1408 #endif
1409 }
1410
1411 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
1412 {
1413         int i, tris, outverts;
1414         if (projectdistance < 0.1)
1415         {
1416                 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1417                 return;
1418         }
1419         if (!numverts || !nummarktris)
1420                 return;
1421         // make sure shadowelements is big enough for this volume
1422         if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1423                 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1424
1425         if (maxvertexupdate < numverts)
1426         {
1427                 maxvertexupdate = numverts;
1428                 if (vertexupdate)
1429                         Mem_Free(vertexupdate);
1430                 if (vertexremap)
1431                         Mem_Free(vertexremap);
1432                 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1433                 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1434                 vertexupdatenum = 0;
1435         }
1436         vertexupdatenum++;
1437         if (vertexupdatenum == 0)
1438         {
1439                 vertexupdatenum = 1;
1440                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1441                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1442         }
1443
1444         for (i = 0;i < nummarktris;i++)
1445                 shadowmark[marktris[i]] = shadowmarkcount;
1446
1447         if (r_shadow_compilingrtlight)
1448         {
1449                 // if we're compiling an rtlight, capture the mesh
1450                 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1451                 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1452                 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1453                 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1454         }
1455         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1456         {
1457                 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1458                 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1459                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1460         }
1461         else
1462         {
1463                 // decide which type of shadow to generate and set stencil mode
1464                 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1465                 // generate the sides or a solid volume, depending on type
1466                 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1467                         tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1468                 else
1469                         tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1470                 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1471                 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1472                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1473                 {
1474                         // increment stencil if frontface is infront of depthbuffer
1475                         GL_CullFace(r_refdef.view.cullface_front);
1476                         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1477                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1478                         // decrement stencil if backface is infront of depthbuffer
1479                         GL_CullFace(r_refdef.view.cullface_back);
1480                         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1481                 }
1482                 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1483                 {
1484                         // decrement stencil if backface is behind depthbuffer
1485                         GL_CullFace(r_refdef.view.cullface_front);
1486                         R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1487                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1488                         // increment stencil if frontface is behind depthbuffer
1489                         GL_CullFace(r_refdef.view.cullface_back);
1490                         R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1491                 }
1492                 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1493                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1494         }
1495 }
1496
1497 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1498 {
1499         // p1, p2, p3 are in the cubemap's local coordinate system
1500         // bias = border/(size - border)
1501         int mask = 0x3F;
1502
1503         float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1504                   dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1505                   dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1506         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1507                 mask &= (3<<4)
1508                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1509                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1510                         | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1511         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1512                 mask &= (3<<4)
1513                         | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1514                         | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))                    
1515                         | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1516
1517         dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1518         dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1519         dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1520         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1521                 mask &= (3<<0)
1522                         | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1523                         | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))                    
1524                         | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1525         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1526                 mask &= (3<<0)
1527                         | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1528                         | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1529                         | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1530
1531         dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1532         dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1533         dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1534         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1535                 mask &= (3<<2)
1536                         | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1537                         | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1538                         | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1539         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1540                 mask &= (3<<2)
1541                         | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1542                         | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1543                         | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1544
1545         return mask;
1546 }
1547
1548 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1549 {
1550         vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1551         float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1552         int mask = 0x3F;
1553
1554         VectorSubtract(maxs, mins, radius);
1555         VectorScale(radius, 0.5f, radius);
1556         VectorAdd(mins, radius, center);
1557         Matrix4x4_Transform(worldtolight, center, lightcenter);
1558         Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1559         VectorSubtract(lightcenter, lightradius, pmin);
1560         VectorAdd(lightcenter, lightradius, pmax);
1561
1562         dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1563         dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1564         if(ap1 > bias*an1 && ap2 > bias*an2)
1565                 mask &= (3<<4)
1566                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1567                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1568         if(an1 > bias*ap1 && an2 > bias*ap2)
1569                 mask &= (3<<4)
1570                         | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1571                         | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1572
1573         dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1574         dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1575         if(ap1 > bias*an1 && ap2 > bias*an2)
1576                 mask &= (3<<0)
1577                         | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1578                         | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1579         if(an1 > bias*ap1 && an2 > bias*ap2)
1580                 mask &= (3<<0)
1581                         | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1582                         | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1583
1584         dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1585         dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1586         if(ap1 > bias*an1 && ap2 > bias*an2)
1587                 mask &= (3<<2)
1588                         | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1589                         | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1590         if(an1 > bias*ap1 && an2 > bias*ap2)
1591                 mask &= (3<<2)
1592                         | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1593                         | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1594
1595         return mask;
1596 }
1597
1598 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1599
1600 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1601 {
1602         // p is in the cubemap's local coordinate system
1603         // bias = border/(size - border)
1604         float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1605         float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1606         float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1607         int mask = 0x3F;
1608         if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1609         if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1610         if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1611         if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1612         if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1613         if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1614         return mask;
1615 }
1616
1617 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1618 {
1619         int i;
1620         vec3_t o, p, n;
1621         int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1622         float scale = (size - 2*border)/size, len;
1623         float bias = border / (float)(size - border), dp, dn, ap, an;
1624         // check if cone enclosing side would cross frustum plane
1625         scale = 2 / (scale*scale + 2);
1626         Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1627         for (i = 0;i < 5;i++)
1628         {
1629                 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1630                         continue;
1631                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1632                 len = scale*VectorLength2(n);
1633                 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1634                 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1635                 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1636         }
1637         if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1638         {
1639                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1640                 len = scale*VectorLength2(n);
1641                 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1642                 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1643                 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1644         }
1645         // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1646         // check if frustum corners/origin cross plane sides
1647 #if 1
1648         // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1649         Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1650         dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1651         masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1652         masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1653         dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1654         masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1655         masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1656         dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1657         masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1658         masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1659         for (i = 0;i < 4;i++)
1660         {
1661                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1662                 VectorSubtract(n, p, n);
1663                 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1664                 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1665                 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1666                 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1667                 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1668                 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1669                 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1670                 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1671                 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1672         }
1673 #else
1674         // finite version, assumes corners are a finite distance from origin dependent on far plane
1675         for (i = 0;i < 5;i++)
1676         {
1677                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1678                 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1679                 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1680                 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1681                 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1682                 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1683                 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1684                 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1685                 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1686                 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1687         }
1688 #endif
1689         return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1690 }
1691
1692 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)
1693 {
1694         int t, tend;
1695         const int *e;
1696         const float *v[3];
1697         float normal[3];
1698         vec3_t p[3];
1699         float bias;
1700         int mask, surfacemask = 0;
1701         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1702                 return 0;
1703         bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1704         tend = firsttriangle + numtris;
1705         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1706         {
1707                 // surface box entirely inside light box, no box cull
1708                 if (projectdirection)
1709                 {
1710                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1711                         {
1712                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1713                                 TriangleNormal(v[0], v[1], v[2], normal);
1714                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1715                                 {
1716                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1717                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1718                                         surfacemask |= mask;
1719                                         if(totals)
1720                                         {
1721                                                 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;
1722                                                 shadowsides[numshadowsides] = mask;
1723                                                 shadowsideslist[numshadowsides++] = t;
1724                                         }
1725                                 }
1726                         }
1727                 }
1728                 else
1729                 {
1730                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1731                         {
1732                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1733                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1734                                 {
1735                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1736                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1737                                         surfacemask |= mask;
1738                                         if(totals)
1739                                         {
1740                                                 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;
1741                                                 shadowsides[numshadowsides] = mask;
1742                                                 shadowsideslist[numshadowsides++] = t;
1743                                         }
1744                                 }
1745                         }
1746                 }
1747         }
1748         else
1749         {
1750                 // surface box not entirely inside light box, cull each triangle
1751                 if (projectdirection)
1752                 {
1753                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1754                         {
1755                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1756                                 TriangleNormal(v[0], v[1], v[2], normal);
1757                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1758                                  && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1759                                 {
1760                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1761                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1762                                         surfacemask |= mask;
1763                                         if(totals)
1764                                         {
1765                                                 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;
1766                                                 shadowsides[numshadowsides] = mask;
1767                                                 shadowsideslist[numshadowsides++] = t;
1768                                         }
1769                                 }
1770                         }
1771                 }
1772                 else
1773                 {
1774                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1775                         {
1776                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1777                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1778                                  && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1779                                 {
1780                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1781                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1782                                         surfacemask |= mask;
1783                                         if(totals)
1784                                         {
1785                                                 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;
1786                                                 shadowsides[numshadowsides] = mask;
1787                                                 shadowsideslist[numshadowsides++] = t;
1788                                         }
1789                                 }
1790                         }
1791                 }
1792         }
1793         return surfacemask;
1794 }
1795
1796 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)
1797 {
1798         int i, j, outtriangles = 0;
1799         int *outelement3i[6];
1800         if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1801                 return;
1802         outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1803         // make sure shadowelements is big enough for this mesh
1804         if (maxshadowtriangles < outtriangles)
1805                 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1806
1807         // compute the offset and size of the separate index lists for each cubemap side
1808         outtriangles = 0;
1809         for (i = 0;i < 6;i++)
1810         {
1811                 outelement3i[i] = shadowelements + outtriangles * 3;
1812                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1813                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1814                 outtriangles += sidetotals[i];
1815         }
1816
1817         // gather up the (sparse) triangles into separate index lists for each cubemap side
1818         for (i = 0;i < numsidetris;i++)
1819         {
1820                 const int *element = elements + sidetris[i] * 3;
1821                 for (j = 0;j < 6;j++)
1822                 {
1823                         if (sides[i] & (1 << j))
1824                         {
1825                                 outelement3i[j][0] = element[0];
1826                                 outelement3i[j][1] = element[1];
1827                                 outelement3i[j][2] = element[2];
1828                                 outelement3i[j] += 3;
1829                         }
1830                 }
1831         }
1832                         
1833         Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1834 }
1835
1836 static void R_Shadow_MakeTextures_MakeCorona(void)
1837 {
1838         float dx, dy;
1839         int x, y, a;
1840         unsigned char pixels[32][32][4];
1841         for (y = 0;y < 32;y++)
1842         {
1843                 dy = (y - 15.5f) * (1.0f / 16.0f);
1844                 for (x = 0;x < 32;x++)
1845                 {
1846                         dx = (x - 15.5f) * (1.0f / 16.0f);
1847                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1848                         a = bound(0, a, 255);
1849                         pixels[y][x][0] = a;
1850                         pixels[y][x][1] = a;
1851                         pixels[y][x][2] = a;
1852                         pixels[y][x][3] = 255;
1853                 }
1854         }
1855         r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1856 }
1857
1858 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1859 {
1860         float dist = sqrt(x*x+y*y+z*z);
1861         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1862         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1863         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1864 }
1865
1866 static void R_Shadow_MakeTextures(void)
1867 {
1868         int x, y, z;
1869         float intensity, dist;
1870         unsigned int *data;
1871         R_Shadow_FreeShadowMaps();
1872         R_FreeTexturePool(&r_shadow_texturepool);
1873         r_shadow_texturepool = R_AllocTexturePool();
1874         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1875         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1876         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1877         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1878         for (x = 0;x <= ATTENTABLESIZE;x++)
1879         {
1880                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1881                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1882                 r_shadow_attentable[x] = bound(0, intensity, 1);
1883         }
1884         // 1D gradient texture
1885         for (x = 0;x < ATTEN1DSIZE;x++)
1886                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1887         r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1888         // 2D circle texture
1889         for (y = 0;y < ATTEN2DSIZE;y++)
1890                 for (x = 0;x < ATTEN2DSIZE;x++)
1891                         data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
1892         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1893         // 3D sphere texture
1894         if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1895         {
1896                 for (z = 0;z < ATTEN3DSIZE;z++)
1897                         for (y = 0;y < ATTEN3DSIZE;y++)
1898                                 for (x = 0;x < ATTEN3DSIZE;x++)
1899                                         data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
1900                 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1901         }
1902         else
1903                 r_shadow_attenuation3dtexture = NULL;
1904         Mem_Free(data);
1905
1906         R_Shadow_MakeTextures_MakeCorona();
1907
1908         // Editor light sprites
1909         r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1910         "................"
1911         ".3............3."
1912         "..5...2332...5.."
1913         "...7.3....3.7..."
1914         "....7......7...."
1915         "...3.7....7.3..."
1916         "..2...7..7...2.."
1917         "..3..........3.."
1918         "..3..........3.."
1919         "..2...7..7...2.."
1920         "...3.7....7.3..."
1921         "....7......7...."
1922         "...7.3....3.7..."
1923         "..5...2332...5.."
1924         ".3............3."
1925         "................"
1926         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1927         r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1928         "................"
1929         "................"
1930         "......1111......"
1931         "....11233211...."
1932         "...1234554321..."
1933         "...1356776531..."
1934         "..124677776421.."
1935         "..135777777531.."
1936         "..135777777531.."
1937         "..124677776421.."
1938         "...1356776531..."
1939         "...1234554321..."
1940         "....11233211...."
1941         "......1111......"
1942         "................"
1943         "................"
1944         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1945         r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1946         "................"
1947         "................"
1948         "......1111......"
1949         "....11233211...."
1950         "...1234554321..."
1951         "...1356226531..."
1952         "..12462..26421.."
1953         "..1352....2531.."
1954         "..1352....2531.."
1955         "..12462..26421.."
1956         "...1356226531..."
1957         "...1234554321..."
1958         "....11233211...."
1959         "......1111......"
1960         "................"
1961         "................"
1962         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1963         r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1964         "................"
1965         "................"
1966         "......2772......"
1967         "....27755772...."
1968         "..277533335772.."
1969         "..753333333357.."
1970         "..777533335777.."
1971         "..735775577537.."
1972         "..733357753337.."
1973         "..733337733337.."
1974         "..753337733357.."
1975         "..277537735772.."
1976         "....27777772...."
1977         "......2772......"
1978         "................"
1979         "................"
1980         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1981         r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1982         "................"
1983         "................"
1984         "......2772......"
1985         "....27722772...."
1986         "..2772....2772.."
1987         "..72........27.."
1988         "..7772....2777.."
1989         "..7.27722772.7.."
1990         "..7...2772...7.."
1991         "..7....77....7.."
1992         "..72...77...27.."
1993         "..2772.77.2772.."
1994         "....27777772...."
1995         "......2772......"
1996         "................"
1997         "................"
1998         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1999         r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
2000         "................"
2001         ".777752..257777."
2002         ".742........247."
2003         ".72..........27."
2004         ".7............7."
2005         ".5............5."
2006         ".2............2."
2007         "................"
2008         "................"
2009         ".2............2."
2010         ".5............5."
2011         ".7............7."
2012         ".72..........27."
2013         ".742........247."
2014         ".777752..257777."
2015         "................"
2016         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2017 }
2018
2019 void R_Shadow_ValidateCvars(void)
2020 {
2021         if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2022                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2023         if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2024                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2025         if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2026                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2027 }
2028
2029 void R_Shadow_RenderMode_Begin(void)
2030 {
2031 #if 0
2032         GLint drawbuffer;
2033         GLint readbuffer;
2034 #endif
2035         R_Shadow_ValidateCvars();
2036
2037         if (!r_shadow_attenuation2dtexture
2038          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2039          || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2040          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2041                 R_Shadow_MakeTextures();
2042
2043         CHECKGLERROR
2044         R_Mesh_ResetTextureState();
2045         GL_BlendFunc(GL_ONE, GL_ZERO);
2046         GL_DepthRange(0, 1);
2047         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2048         GL_DepthTest(true);
2049         GL_DepthMask(false);
2050         GL_Color(0, 0, 0, 1);
2051         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2052         
2053         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2054
2055         if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2056         {
2057                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2058                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2059         }
2060         else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2061         {
2062                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2063                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2064         }
2065         else
2066         {
2067                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2068                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2069         }
2070
2071         switch(vid.renderpath)
2072         {
2073         case RENDERPATH_GL20:
2074         case RENDERPATH_D3D9:
2075         case RENDERPATH_D3D10:
2076         case RENDERPATH_D3D11:
2077         case RENDERPATH_SOFT:
2078         case RENDERPATH_GLES2:
2079                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2080                 break;
2081         case RENDERPATH_GL11:
2082         case RENDERPATH_GL13:
2083         case RENDERPATH_GLES1:
2084                 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2085                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2086                 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2087                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2088                 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2089                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2090                 else
2091                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2092                 break;
2093         }
2094
2095         CHECKGLERROR
2096 #if 0
2097         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2098         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2099         r_shadow_drawbuffer = drawbuffer;
2100         r_shadow_readbuffer = readbuffer;
2101 #endif
2102         r_shadow_cullface_front = r_refdef.view.cullface_front;
2103         r_shadow_cullface_back = r_refdef.view.cullface_back;
2104 }
2105
2106 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2107 {
2108         rsurface.rtlight = rtlight;
2109 }
2110
2111 void R_Shadow_RenderMode_Reset(void)
2112 {
2113         R_Mesh_ResetTextureState();
2114         R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2115         R_SetViewport(&r_refdef.view.viewport);
2116         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2117         GL_DepthRange(0, 1);
2118         GL_DepthTest(true);
2119         GL_DepthMask(false);
2120         GL_DepthFunc(GL_LEQUAL);
2121         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2122         r_refdef.view.cullface_front = r_shadow_cullface_front;
2123         r_refdef.view.cullface_back = r_shadow_cullface_back;
2124         GL_CullFace(r_refdef.view.cullface_back);
2125         GL_Color(1, 1, 1, 1);
2126         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2127         GL_BlendFunc(GL_ONE, GL_ZERO);
2128         R_SetupShader_Generic_NoTexture(false, false);
2129         r_shadow_usingshadowmap2d = false;
2130         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2131 }
2132
2133 void R_Shadow_ClearStencil(void)
2134 {
2135         GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2136         r_refdef.stats[r_stat_lights_clears]++;
2137 }
2138
2139 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2140 {
2141         r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2142         if (r_shadow_rendermode == mode)
2143                 return;
2144         R_Shadow_RenderMode_Reset();
2145         GL_DepthFunc(GL_LESS);
2146         GL_ColorMask(0, 0, 0, 0);
2147         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2148         GL_CullFace(GL_NONE);
2149         R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2150         r_shadow_rendermode = mode;
2151         switch(mode)
2152         {
2153         default:
2154                 break;
2155         case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2156         case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2157                 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2158                 break;
2159         case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2160         case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2161                 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2162                 break;
2163         }
2164 }
2165
2166 static void R_Shadow_MakeVSDCT(void)
2167 {
2168         // maps to a 2x3 texture rectangle with normalized coordinates
2169         // +-
2170         // XX
2171         // YY
2172         // ZZ
2173         // stores abs(dir.xy), offset.xy/2.5
2174         unsigned char data[4*6] =
2175         {
2176                 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2177                 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2178                 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2179                 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2180                 0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2181                 0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2182         };
2183         r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2184 }
2185
2186 static void R_Shadow_MakeShadowMap(int texturesize)
2187 {
2188         switch (r_shadow_shadowmode)
2189         {
2190         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2191                 if (r_shadow_shadowmap2ddepthtexture) return;
2192                 if (r_fb.usedepthtextures)
2193                 {
2194                         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);
2195                         r_shadow_shadowmap2ddepthbuffer = NULL;
2196                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2197                 }
2198                 else
2199                 {
2200                         r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2201                         r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2202                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2203                 }
2204                 break;
2205         default:
2206                 return;
2207         }
2208 }
2209
2210 void R_Shadow_ClearShadowMapTexture(void)
2211 {
2212         r_viewport_t viewport;
2213         float clearcolor[4];
2214
2215         // if they don't exist, create our textures now
2216         if (!r_shadow_shadowmap2ddepthtexture)
2217                 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2218         if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2219                 R_Shadow_MakeVSDCT();
2220
2221         // we're setting up to render shadowmaps, so change rendermode
2222         r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2223
2224         R_Mesh_ResetTextureState();
2225         R_Shadow_RenderMode_Reset();
2226         if (r_shadow_shadowmap2ddepthbuffer)
2227                 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2228         else
2229                 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2230         R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2231         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2232         GL_DepthMask(true);
2233         GL_DepthTest(true);
2234
2235         // we have to set a viewport to clear anything in some renderpaths (D3D)
2236         R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2237         R_SetViewport(&viewport);
2238         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2239         if (r_shadow_shadowmap2ddepthbuffer)
2240                 GL_ColorMask(1, 1, 1, 1);
2241         else
2242                 GL_ColorMask(0, 0, 0, 0);
2243         switch (vid.renderpath)
2244         {
2245         case RENDERPATH_GL11:
2246         case RENDERPATH_GL13:
2247         case RENDERPATH_GL20:
2248         case RENDERPATH_SOFT:
2249         case RENDERPATH_GLES1:
2250         case RENDERPATH_GLES2:
2251                 GL_CullFace(r_refdef.view.cullface_back);
2252                 break;
2253         case RENDERPATH_D3D9:
2254         case RENDERPATH_D3D10:
2255         case RENDERPATH_D3D11:
2256                 // we invert the cull mode because we flip the projection matrix
2257                 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2258                 GL_CullFace(r_refdef.view.cullface_front);
2259                 break;
2260         }
2261         Vector4Set(clearcolor, 1, 1, 1, 1);
2262         if (r_shadow_shadowmap2ddepthbuffer)
2263                 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2264         else
2265                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2266 }
2267
2268 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2269 {
2270         int size = rsurface.rtlight->shadowmapatlassidesize;
2271         float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2272         float farclip = 1.0f;
2273         float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2274         r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2275         r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2276         r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2277         r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2278         r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2279         r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2280         r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2281         r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2282         if (r_shadow_shadowmap2ddepthbuffer)
2283         {
2284                 // completely different meaning than in depthtexture approach
2285                 r_shadow_lightshadowmap_parameters[1] = 0;
2286                 r_shadow_lightshadowmap_parameters[3] = -bias;
2287         }
2288 }
2289
2290 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2291 {
2292         float nearclip, farclip, bias;
2293         r_viewport_t viewport;
2294         int flipped;
2295         float clearcolor[4];
2296
2297         if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2298         {
2299                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2300
2301                 R_Mesh_ResetTextureState();
2302                 R_Shadow_RenderMode_Reset();
2303                 if (r_shadow_shadowmap2ddepthbuffer)
2304                         R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2305                 else
2306                         R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2307                 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2308                 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2309                 GL_DepthMask(true);
2310                 GL_DepthTest(true);
2311         }
2312
2313         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2314         farclip = 1.0f;
2315         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2316
2317         R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2318         R_SetViewport(&viewport);
2319         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2320         flipped = (side & 1) ^ (side >> 2);
2321         r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2322         r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2323
2324         Vector4Set(clearcolor, 1,1,1,1);
2325         if (r_shadow_shadowmap2ddepthbuffer)
2326                 GL_ColorMask(1,1,1,1);
2327         else
2328                 GL_ColorMask(0,0,0,0);
2329         switch(vid.renderpath)
2330         {
2331         case RENDERPATH_GL11:
2332         case RENDERPATH_GL13:
2333         case RENDERPATH_GL20:
2334         case RENDERPATH_SOFT:
2335         case RENDERPATH_GLES1:
2336         case RENDERPATH_GLES2:
2337                 GL_CullFace(r_refdef.view.cullface_back);
2338                 break;
2339         case RENDERPATH_D3D9:
2340         case RENDERPATH_D3D10:
2341         case RENDERPATH_D3D11:
2342                 // we invert the cull mode because we flip the projection matrix
2343                 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2344                 GL_CullFace(r_refdef.view.cullface_front);
2345                 break;
2346         }
2347
2348         // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2349         r_shadow_shadowmapside = side;
2350 }
2351
2352 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2353 {
2354         R_Mesh_ResetTextureState();
2355         if (transparent)
2356         {
2357                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2358                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2359                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2360                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2361         }
2362         if (shadowmapping)
2363                 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2364         R_Shadow_RenderMode_Reset();
2365         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2366         if (!transparent)
2367                 GL_DepthFunc(GL_EQUAL);
2368         // do global setup needed for the chosen lighting mode
2369         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2370                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2371         r_shadow_usingshadowmap2d = shadowmapping;
2372         r_shadow_rendermode = r_shadow_lightingrendermode;
2373         // only draw light where this geometry was already rendered AND the
2374         // stencil is 128 (values other than this mean shadow)
2375         if (stenciltest)
2376                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2377         else
2378                 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2379 }
2380
2381 static const unsigned short bboxelements[36] =
2382 {
2383         5, 1, 3, 5, 3, 7,
2384         6, 2, 0, 6, 0, 4,
2385         7, 3, 2, 7, 2, 6,
2386         4, 0, 1, 4, 1, 5,
2387         4, 5, 7, 4, 7, 6,
2388         1, 0, 2, 1, 2, 3,
2389 };
2390
2391 static const float bboxpoints[8][3] =
2392 {
2393         {-1,-1,-1},
2394         { 1,-1,-1},
2395         {-1, 1,-1},
2396         { 1, 1,-1},
2397         {-1,-1, 1},
2398         { 1,-1, 1},
2399         {-1, 1, 1},
2400         { 1, 1, 1},
2401 };
2402
2403 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2404 {
2405         int i;
2406         float vertex3f[8*3];
2407         const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2408 // do global setup needed for the chosen lighting mode
2409         R_Shadow_RenderMode_Reset();
2410         r_shadow_rendermode = r_shadow_lightingrendermode;
2411         R_EntityMatrix(&identitymatrix);
2412         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2413         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2414         if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2415                 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2416         else
2417                 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2418
2419         r_shadow_usingshadowmap2d = shadowmapping;
2420
2421         // render the lighting
2422         R_SetupShader_DeferredLight(rsurface.rtlight);
2423         for (i = 0;i < 8;i++)
2424                 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2425         GL_ColorMask(1,1,1,1);
2426         GL_DepthMask(false);
2427         GL_DepthRange(0, 1);
2428         GL_PolygonOffset(0, 0);
2429         GL_DepthTest(true);
2430         GL_DepthFunc(GL_GREATER);
2431         GL_CullFace(r_refdef.view.cullface_back);
2432         R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2433         R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2434 }
2435
2436 #define MAXBOUNCEGRIDSPLATSIZE 7
2437 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2438
2439 // these are temporary data per-frame, sorted and performed in a more
2440 // cache-friendly order than the original photons
2441 typedef struct r_shadow_bouncegrid_splatpath_s
2442 {
2443         vec3_t point;
2444         vec3_t step;
2445         vec3_t splatcolor;
2446         vec3_t splatdir;
2447         vec_t splatintensity;
2448         vec_t splatsize_current;
2449         vec_t splatsize_perstep;
2450         int remainingsplats;
2451 }
2452 r_shadow_bouncegrid_splatpath_t;
2453
2454 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
2455 {
2456         int bestaxis;
2457         int numsplats;
2458         float len;
2459         float ilen;
2460         vec3_t start;
2461         vec3_t end;
2462         vec3_t diff;
2463         vec3_t originaldir;
2464         r_shadow_bouncegrid_splatpath_t *path;
2465
2466         // cull paths that fail R_CullBox in dynamic mode
2467         if (!r_shadow_bouncegrid_state.settings.staticmode
2468          && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2469         {
2470                 vec3_t cullmins, cullmaxs;
2471                 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2472                 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2473                 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2474                 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2475                 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2476                 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2477                 if (R_CullBox(cullmins, cullmaxs))
2478                         return;
2479         }
2480
2481         // if the light path is going upward, reverse it - we always draw down.
2482         if (originalend[2] < originalstart[2])
2483         {
2484                 VectorCopy(originalend, start);
2485                 VectorCopy(originalstart, end);
2486         }
2487         else
2488         {
2489                 VectorCopy(originalstart, start);
2490                 VectorCopy(originalend, end);
2491         }
2492
2493         // transform to texture pixels
2494         start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2495         start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2496         start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2497         end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2498         end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2499         end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2500
2501         // check if we need to grow the splatpaths array
2502         if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2503         {
2504                 // double the limit, this will persist from frame to frame so we don't
2505                 // make the same mistake each time
2506                 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2507                 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2508                         r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2509                 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);
2510         }
2511
2512         // divide a series of splats along the length using the maximum axis
2513         VectorSubtract(end, start, diff);
2514         // pick the best axis to trace along
2515         bestaxis = 0;
2516         if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2517                 bestaxis = 1;
2518         if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2519                 bestaxis = 2;
2520         len = fabs(diff[bestaxis]);
2521         ilen = 1.0f / len;
2522         numsplats = (int)(floor(len + 0.5f));
2523         // sanity limits
2524         numsplats = bound(0, numsplats, 1024);
2525
2526         VectorSubtract(originalstart, originalend, originaldir);
2527         VectorNormalize(originaldir);
2528
2529         path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2530         VectorCopy(start, path->point);
2531         VectorScale(diff, ilen, path->step);
2532         VectorCopy(color, path->splatcolor);
2533         VectorCopy(originaldir, path->splatdir);
2534         path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
2535         path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
2536         path->splatintensity = VectorLength(color);
2537         path->remainingsplats = numsplats;
2538 }
2539
2540 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2541 {
2542         qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2543         int lightindex;
2544         int range;
2545         dlight_t *light;
2546         rtlight_t *rtlight;
2547         vec3_t lightcolor;
2548
2549         // see if there are really any lights to render...
2550         if (enable && r_shadow_bouncegrid_static.integer)
2551         {
2552                 enable = false;
2553                 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2554                 for (lightindex = 0;lightindex < range;lightindex++)
2555                 {
2556                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2557                         if (!light || !(light->flags & flag))
2558                                 continue;
2559                         rtlight = &light->rtlight;
2560                         // when static, we skip styled lights because they tend to change...
2561                         if (rtlight->style > 0)
2562                                 continue;
2563                         VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2564                         if (!VectorLength2(lightcolor))
2565                                 continue;
2566                         enable = true;
2567                         break;
2568                 }
2569         }
2570
2571         return enable;
2572 }
2573
2574 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2575 {
2576         qboolean s = r_shadow_bouncegrid_static.integer != 0;
2577         float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
2578         float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
2579         float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2580
2581         // prevent any garbage in alignment padded areas as we'll be using memcmp
2582         memset(settings, 0, sizeof(*settings));
2583
2584         // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2585         settings->staticmode                    = s;
2586         settings->blur                          = r_shadow_bouncegrid_blur.integer != 0;
2587         settings->floatcolors                   = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2588         settings->lightpathsize_initial         = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
2589         settings->lightpathsize_conespread      = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
2590         settings->bounceanglediffuse            = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2591         settings->directionalshading            = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2592         settings->dlightparticlemultiplier      = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2593         settings->hitmodels                     = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2594         settings->includedirectlighting         = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2595         settings->lightradiusscale              = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2596         settings->maxbounce                     = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2597         settings->particlebounceintensity       = r_shadow_bouncegrid_particlebounceintensity.value;
2598         settings->particleintensity             = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2599         settings->maxphotons                    = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2600         settings->energyperphoton               = spacing * spacing / quality;
2601         settings->spacing[0]                    = spacing;
2602         settings->spacing[1]                    = spacing;
2603         settings->spacing[2]                    = spacing;
2604         settings->rng_type                      = r_shadow_bouncegrid_rng_type.integer;
2605         settings->rng_seed                      = r_shadow_bouncegrid_rng_seed.integer;
2606         settings->bounceminimumintensity2       = bounceminimumintensity * bounceminimumintensity;
2607         settings->bounceminimumintensity2       = bounceminimumintensity * bounceminimumintensity;
2608         settings->normalizevectors              = r_shadow_bouncegrid_normalizevectors.integer != 0;
2609
2610         // bound the values for sanity
2611         settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2612         settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2613         settings->maxbounce = bound(0, settings->maxbounce, 16);
2614         settings->spacing[0] = bound(1, settings->spacing[0], 512);
2615         settings->spacing[1] = bound(1, settings->spacing[1], 512);
2616         settings->spacing[2] = bound(1, settings->spacing[2], 512);
2617 }
2618
2619 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2620 {
2621         float m[16];
2622         int c[4];
2623         int resolution[3];
2624         int numpixels;
2625         vec3_t ispacing;
2626         vec3_t maxs;
2627         vec3_t mins;
2628         vec3_t size;
2629         vec3_t spacing;
2630         r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2631
2632         // get the spacing values
2633         spacing[0] = settings->spacing[0];
2634         spacing[1] = settings->spacing[1];
2635         spacing[2] = settings->spacing[2];
2636         ispacing[0] = 1.0f / spacing[0];
2637         ispacing[1] = 1.0f / spacing[1];
2638         ispacing[2] = 1.0f / spacing[2];
2639
2640         // calculate texture size enclosing entire world bounds at the spacing
2641         if (r_refdef.scene.worldmodel)
2642         {
2643                 int lightindex;
2644                 int range;
2645                 qboolean bounds_set = false;
2646                 dlight_t *light;
2647                 rtlight_t *rtlight;
2648
2649                 // calculate bounds enclosing world lights as they should be noticably tighter 
2650                 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
2651                 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2652                 for (lightindex = 0;lightindex < range;lightindex++)
2653                 {
2654                         const vec_t *rtlmins, *rtlmaxs;
2655
2656                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2657                         if (!light)
2658                                 continue;
2659
2660                         rtlight = &light->rtlight;
2661                         rtlmins = rtlight->cullmins;
2662                         rtlmaxs = rtlight->cullmaxs;
2663
2664                         if (!bounds_set)
2665                         {
2666                                 VectorCopy(rtlmins, mins);
2667                                 VectorCopy(rtlmaxs, maxs);
2668                                 bounds_set = true;
2669                         }
2670                         else
2671                         {
2672                                 mins[0] = min(mins[0], rtlmins[0]);
2673                                 mins[1] = min(mins[1], rtlmins[1]);
2674                                 mins[2] = min(mins[2], rtlmins[2]);
2675                                 maxs[0] = max(maxs[0], rtlmaxs[0]);
2676                                 maxs[1] = max(maxs[1], rtlmaxs[1]);
2677                                 maxs[2] = max(maxs[2], rtlmaxs[2]);
2678                         }
2679                 }
2680
2681                 // limit to no larger than the world bounds
2682                 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
2683                 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
2684                 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
2685                 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
2686                 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
2687                 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
2688
2689                 VectorMA(mins, -2.0f, spacing, mins);
2690                 VectorMA(maxs, 2.0f, spacing, maxs);
2691         }
2692         else
2693         {
2694                 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2695                 VectorSet(maxs,  1048576.0f,  1048576.0f,  1048576.0f);
2696         }
2697         VectorSubtract(maxs, mins, size);
2698         // now we can calculate the resolution we want
2699         c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2700         c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2701         c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2702         // figure out the exact texture size (honoring power of 2 if required)
2703         c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2704         c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2705         c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2706         if (vid.support.arb_texture_non_power_of_two)
2707         {
2708                 resolution[0] = c[0];
2709                 resolution[1] = c[1];
2710                 resolution[2] = c[2];
2711         }
2712         else
2713         {
2714                 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2715                 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2716                 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2717         }
2718         size[0] = spacing[0] * resolution[0];
2719         size[1] = spacing[1] * resolution[1];
2720         size[2] = spacing[2] * resolution[2];
2721
2722         // if dynamic we may or may not want to use the world bounds
2723         // if the dynamic size is smaller than the world bounds, use it instead
2724         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]))
2725         {
2726                 // we know the resolution we want
2727                 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2728                 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2729                 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2730                 // now we can calculate the texture size (power of 2 if required)
2731                 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2732                 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2733                 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2734                 if (vid.support.arb_texture_non_power_of_two)
2735                 {
2736                         resolution[0] = c[0];
2737                         resolution[1] = c[1];
2738                         resolution[2] = c[2];
2739                 }
2740                 else
2741                 {
2742                         for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2743                         for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2744                         for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2745                 }
2746                 size[0] = spacing[0] * resolution[0];
2747                 size[1] = spacing[1] * resolution[1];
2748                 size[2] = spacing[2] * resolution[2];
2749                 // center the rendering on the view
2750                 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2751                 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2752                 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2753         }
2754
2755         // recalculate the maxs in case the resolution was not satisfactory
2756         VectorAdd(mins, size, maxs);
2757
2758         // check if this changed the texture size
2759         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);
2760         r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2761         VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2762         VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2763         VectorCopy(size, r_shadow_bouncegrid_state.size);
2764         VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2765         VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2766         VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2767
2768         // reallocate pixels for this update if needed...
2769         r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2770         r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2771         r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2772         numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2773         if (r_shadow_bouncegrid_state.numpixels != numpixels)
2774         {
2775                 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2776                 r_shadow_bouncegrid_state.highpixels = NULL;
2777                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2778                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2779                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2780                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2781                 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2782                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2783                 r_shadow_bouncegrid_state.numpixels = numpixels;
2784         }
2785
2786         // update the bouncegrid matrix to put it in the world properly
2787         memset(m, 0, sizeof(m));
2788         m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2789         m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2790         m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2791         m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2792         m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2793         m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2794         m[15] = 1.0f;
2795         Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2796 }
2797
2798 // enumerate world rtlights and sum the overall amount of light in the world,
2799 // from that we can calculate a scaling factor to fairly distribute photons
2800 // to all the lights
2801 //
2802 // this modifies rtlight->photoncolor and rtlight->photons
2803 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2804 {
2805         float normalphotonscaling;
2806         float photonscaling;
2807         float photonintensity;
2808         float photoncount = 0.0f;
2809         float lightintensity;
2810         float radius;
2811         float s;
2812         float w;
2813         vec3_t cullmins;
2814         vec3_t cullmaxs;
2815         unsigned int lightindex;
2816         dlight_t *light;
2817         rtlight_t *rtlight;
2818         normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2819         for (lightindex = 0;lightindex < range2;lightindex++)
2820         {
2821                 if (lightindex < range)
2822                 {
2823                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2824                         if (!light)
2825                                 continue;
2826                         rtlight = &light->rtlight;
2827                         VectorClear(rtlight->bouncegrid_photoncolor);
2828                         rtlight->bouncegrid_photons = 0;
2829                         rtlight->bouncegrid_hits = 0;
2830                         rtlight->bouncegrid_traces = 0;
2831                         rtlight->bouncegrid_effectiveradius = 0;
2832                         if (!(light->flags & flag))
2833                                 continue;
2834                         if (settings->staticmode)
2835                         {
2836                                 // when static, we skip styled lights because they tend to change...
2837                                 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2838                                         continue;
2839                         }
2840                         else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2841                                 continue;
2842                 }
2843                 else
2844                 {
2845                         rtlight = r_refdef.scene.lights[lightindex - range];
2846                         VectorClear(rtlight->bouncegrid_photoncolor);
2847                         rtlight->bouncegrid_photons = 0;
2848                         rtlight->bouncegrid_hits = 0;
2849                         rtlight->bouncegrid_traces = 0;
2850                         rtlight->bouncegrid_effectiveradius = 0;
2851                 }
2852                 // draw only visible lights (major speedup)
2853                 radius = rtlight->radius * settings->lightradiusscale;
2854                 cullmins[0] = rtlight->shadoworigin[0] - radius;
2855                 cullmins[1] = rtlight->shadoworigin[1] - radius;
2856                 cullmins[2] = rtlight->shadoworigin[2] - radius;
2857                 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2858                 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2859                 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2860                 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2861                 if (!settings->staticmode)
2862                 {
2863                         // skip if the expanded light box does not touch any visible leafs
2864                         if (r_refdef.scene.worldmodel
2865                                 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2866                                 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2867                                 continue;
2868                         // skip if the expanded light box is not visible to traceline
2869                         // note that PrepareLight already did this check but for a smaller box, so we
2870                         // end up casting more traces per frame per light when using bouncegrid, which
2871                         // is probably fine (and they use the same timer)
2872                         if (r_shadow_culllights_trace.integer)
2873                         {
2874                                 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_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
2875                                         rtlight->trace_timer = realtime;
2876                                 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2877                                         return;
2878                         }
2879                         // skip if expanded light box is offscreen
2880                         if (R_CullBox(cullmins, cullmaxs))
2881                                 continue;
2882                         // skip if overall light intensity is zero
2883                         if (w * VectorLength2(rtlight->color) == 0.0f)
2884                                 continue;
2885                 }
2886                 // a light that does not emit any light before style is applied, can be
2887                 // skipped entirely (it may just be a corona)
2888                 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2889                         continue;
2890                 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2891                 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2892                 // skip lights that will emit no photons
2893                 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2894                         continue;
2895                 // shoot particles from this light
2896                 // use a calculation for the number of particles that will not
2897                 // vary with lightstyle, otherwise we get randomized particle
2898                 // distribution, the seeded random is only consistent for a
2899                 // consistent number of particles on this light...
2900                 s = rtlight->radius;
2901                 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2902                 if (lightindex >= range)
2903                         lightintensity *= settings->dlightparticlemultiplier;
2904                 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2905                 photoncount += rtlight->bouncegrid_photons;
2906                 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2907                 // if the lightstyle happens to be off right now, we can skip actually
2908                 // firing the photons, but we did have to count them in the total.
2909                 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2910                 //      rtlight->bouncegrid_photons = 0;
2911         }
2912         // the user provided an energyperphoton value which we try to use
2913         // if that results in too many photons to shoot this frame, then we cap it
2914         // which causes photons to appear/disappear from frame to frame, so we don't
2915         // like doing that in the typical case
2916         photonscaling = 1.0f;
2917         photonintensity = 1.0f;
2918         if (photoncount > settings->maxphotons)
2919         {
2920                 photonscaling = settings->maxphotons / photoncount;
2921                 photonintensity = 1.0f / photonscaling;
2922         }
2923
2924         // modify the lights to reflect our computed scaling
2925         for (lightindex = 0; lightindex < range2; lightindex++)
2926         {
2927                 if (lightindex < range)
2928                 {
2929                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2930                         if (!light)
2931                                 continue;
2932                         rtlight = &light->rtlight;
2933                 }
2934                 else
2935                         rtlight = r_refdef.scene.lights[lightindex - range];
2936                 rtlight->bouncegrid_photons *= photonscaling;
2937                 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2938         }
2939 }
2940
2941 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2942 {
2943         r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2944         r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2945         // we only really care about sorting by Z
2946         if (a->point[2] < b->point[2])
2947                 return -1;
2948         if (a->point[2] > b->point[2])
2949                 return 1;
2950         return 0;
2951 }
2952
2953 static void R_Shadow_BounceGrid_ClearPixels(void)
2954 {
2955         // clear the highpixels array we'll be accumulating into
2956         if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2957                 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2958         if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2959                 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2960         r_shadow_bouncegrid_state.highpixels_index = 0;
2961         r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2962         memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2963 }
2964
2965 static void R_Shadow_BounceGrid_PerformSplats(void)
2966 {
2967         r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2968         r_shadow_bouncegrid_splatpath_t *splatpath;
2969         float *highpixels = r_shadow_bouncegrid_state.highpixels;
2970         int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2971         int splatindex;
2972         vec3_t steppos;
2973         vec3_t stepdelta;
2974         vec3_t dir;
2975         vec_t lightpathsize_current;
2976         vec_t lightpathsize_perstep;
2977         float splatcolor[32];
2978         int resolution[3];
2979         int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2980         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2981         int numsteps;
2982         int step;
2983
2984         // hush warnings about uninitialized data - pixelbands doesn't change but...
2985         memset(splatcolor, 0, sizeof(splatcolor));
2986
2987         // we use this a lot, so get a local copy
2988         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2989
2990         // sort the splats before we execute them, to reduce cache misses
2991         if (r_shadow_bouncegrid_sortlightpaths.integer)
2992                 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2993
2994         splatpath = splatpaths;
2995         for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2996         {
2997                 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2998                 // accumulate average shotcolor
2999                 VectorCopy(splatpath->splatdir, dir);
3000                 splatcolor[ 0] = splatpath->splatcolor[0];
3001                 splatcolor[ 1] = splatpath->splatcolor[1];
3002                 splatcolor[ 2] = splatpath->splatcolor[2];
3003                 splatcolor[ 3] = 0.0f;
3004                 if (pixelbands > 1)
3005                 {
3006                         // store bentnormal in case the shader has a use for it,
3007                         // bentnormal is an intensity-weighted average of the directions,
3008                         // and will be normalized on conversion to texture pixels.
3009                         splatcolor[ 4] = dir[0] * splatpath->splatintensity;
3010                         splatcolor[ 5] = dir[1] * splatpath->splatintensity;
3011                         splatcolor[ 6] = dir[2] * splatpath->splatintensity;
3012                         splatcolor[ 7] = splatpath->splatintensity;
3013                         // for each color component (R, G, B) calculate the amount that a
3014                         // direction contributes
3015                         splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
3016                         splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
3017                         splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
3018                         splatcolor[11] = 0.0f;
3019                         splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
3020                         splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
3021                         splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
3022                         splatcolor[15] = 0.0f;
3023                         splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
3024                         splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
3025                         splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
3026                         splatcolor[19] = 0.0f;
3027                         // and do the same for negative directions
3028                         splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
3029                         splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
3030                         splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
3031                         splatcolor[23] = 0.0f;
3032                         splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
3033                         splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
3034                         splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
3035                         splatcolor[27] = 0.0f;
3036                         splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
3037                         splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
3038                         splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
3039                         splatcolor[31] = 0.0f;
3040                 }
3041                 // calculate the number of steps we need to traverse this distance
3042                 VectorCopy(splatpath->point, steppos);
3043                 VectorCopy(splatpath->step, stepdelta);
3044                 numsteps = splatpath->remainingsplats;
3045                 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
3046                 lightpathsize_perstep = splatpath->splatsize_perstep;
3047                 for (step = 0;step < numsteps;step++)
3048                 {
3049                         // the middle row/column/layer of each splat are full intensity
3050                         float splatmins[3];
3051                         float splatmaxs[3];
3052                         if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
3053                                 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
3054                         splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
3055                         splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
3056                         splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
3057                         splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
3058                         splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
3059                         splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
3060                         if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
3061                         {
3062                                 // it is within bounds...  do the real work now
3063                                 int xi, yi, zi, band, row;
3064                                 float pixelpos[3];
3065                                 float w;
3066                                 float *p;
3067                                 float colorscale = 1.0f / lightpathsize_current;
3068                                 r_refdef.stats[r_stat_bouncegrid_splats]++;
3069                                 // accumulate light onto the pixels
3070                                 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
3071                                 {
3072                                         pixelpos[2] = zi + 0.5f;
3073                                         for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3074                                         {
3075                                                 pixelpos[1] = yi + 0.5f;
3076                                                 row = (zi*resolution[1] + yi)*resolution[0];
3077                                                 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3078                                                 {
3079                                                         pixelpos[0] = xi + 0.5f;
3080                                                         // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3081                                                         w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3082                                                         if (w > 0.0f)
3083                                                         {
3084                                                                 if (w > 1.0f)
3085                                                                         w = 1.0f;
3086                                                                 w *= colorscale;
3087                                                                 p = highpixels + 4 * (row + xi);
3088                                                                 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3089                                                                 {
3090                                                                         // add to the pixel color
3091                                                                         p[0] += splatcolor[band * 4 + 0] * w;
3092                                                                         p[1] += splatcolor[band * 4 + 1] * w;
3093                                                                         p[2] += splatcolor[band * 4 + 2] * w;
3094                                                                         p[3] += splatcolor[band * 4 + 3] * w;
3095                                                                 }
3096                                                         }
3097                                                 }
3098                                         }
3099                                 }
3100                         }
3101                         VectorAdd(steppos, stepdelta, steppos);
3102                         lightpathsize_current += lightpathsize_perstep;
3103                 }
3104         }
3105 }
3106
3107 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3108 {
3109         const float *inpixel;
3110         float *outpixel;
3111         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3112         int pixelband;
3113         unsigned int index;
3114         unsigned int x, y, z;
3115         unsigned int resolution[3];
3116         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3117         for (pixelband = 0;pixelband < pixelbands;pixelband++)
3118         {
3119                 for (z = 1;z < resolution[2]-1;z++)
3120                 {
3121                         for (y = 1;y < resolution[1]-1;y++)
3122                         {
3123                                 x = 1;
3124                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3125                                 inpixel = inpixels + 4*index;
3126                                 outpixel = outpixels + 4*index;
3127                                 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3128                                 {
3129                                         outpixel[0] = (inpixel[0] + inpixel[  off] + inpixel[0-off]) * (1.0f / 3.0);
3130                                         outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3131                                         outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3132                                         outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3133                                 }
3134                         }
3135                 }
3136         }
3137 }
3138
3139 static void R_Shadow_BounceGrid_BlurPixels(void)
3140 {
3141         float *pixels[4];
3142         unsigned int resolution[3];
3143
3144         if (!r_shadow_bouncegrid_state.settings.blur)
3145                 return;
3146         
3147         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3148
3149         pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3150         pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3151         pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3152         pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3153
3154         // blur on X
3155         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3156         // blur on Y
3157         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3158         // blur on Z
3159         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3160
3161         // toggle the state, highpixels now points to pixels[3] result
3162         r_shadow_bouncegrid_state.highpixels_index ^= 1;
3163         r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3164 }
3165
3166 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3167 {
3168         int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3169         unsigned char *pixelsbgra8 = NULL;
3170         unsigned char *pixelbgra8;
3171         unsigned short *pixelsrgba16f = NULL;
3172         unsigned short *pixelrgba16f;
3173         float *pixelsrgba32f = NULL;
3174         float *highpixels = r_shadow_bouncegrid_state.highpixels;
3175         float *highpixel;
3176         float *bandpixel;
3177         unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3178         unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3179         unsigned int pixelband;
3180         unsigned int x, y, z;
3181         unsigned int index, bandindex;
3182         unsigned int resolution[3];
3183         int c[4];
3184         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3185
3186         if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3187         {
3188                 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3189                 r_shadow_bouncegrid_state.texture = NULL;
3190         }
3191
3192         // if bentnormals exist, we need to normalize and bias them for the shader
3193         if (pixelbands > 1)
3194         {
3195                 pixelband = 1;
3196                 for (z = 0;z < resolution[2]-1;z++)
3197                 {
3198                         for (y = 0;y < resolution[1]-1;y++)
3199                         {
3200                                 x = 1;
3201                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3202                                 highpixel = highpixels + 4*index;
3203                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3204                                 {
3205                                         // only convert pixels that were hit by photons
3206                                         if (highpixel[3] != 0.0f)
3207                                                 VectorNormalize(highpixel);
3208                                         VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3209                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
3210                                 }
3211                         }
3212                 }
3213         }
3214
3215         // start by clearing the pixels array - we won't be writing to all of it
3216         //
3217         // then process only the pixels that have at least some color, skipping
3218         // the higher bands for speed on pixels that are black
3219         switch (floatcolors)
3220         {
3221         case 0:
3222                 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3223                         r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3224                 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3225                 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3226                 {
3227                         if (pixelband == 1)
3228                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3229                         else
3230                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3231                 }
3232                 for (z = 1;z < resolution[2]-1;z++)
3233                 {
3234                         for (y = 1;y < resolution[1]-1;y++)
3235                         {
3236                                 x = 1;
3237                                 pixelband = 0;
3238                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3239                                 highpixel = highpixels + 4*index;
3240                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3241                                 {
3242                                         // only convert pixels that were hit by photons
3243                                         if (VectorLength2(highpixel))
3244                                         {
3245                                                 // normalize the bentnormal now
3246                                                 if (pixelbands > 1)
3247                                                 {
3248                                                         VectorNormalize(highpixel + pixelsperband * 4);
3249                                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
3250                                                 }
3251                                                 // process all of the pixelbands for this pixel
3252                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3253                                                 {
3254                                                         pixelbgra8 = pixelsbgra8 + 4*bandindex;
3255                                                         bandpixel = highpixels + 4*bandindex;
3256                                                         c[0] = (int)(bandpixel[0]*256.0f);
3257                                                         c[1] = (int)(bandpixel[1]*256.0f);
3258                                                         c[2] = (int)(bandpixel[2]*256.0f);
3259                                                         c[3] = (int)(bandpixel[3]*256.0f);
3260                                                         pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3261                                                         pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3262                                                         pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3263                                                         pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3264                                                 }
3265                                         }
3266                                 }
3267                         }
3268                 }
3269
3270                 if (!r_shadow_bouncegrid_state.createtexture)
3271                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3272                 else
3273                         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);
3274                 break;
3275         case 1:
3276                 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3277                         r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3278                 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3279                 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3280                 for (z = 1;z < resolution[2]-1;z++)
3281                 {
3282                         for (y = 1;y < resolution[1]-1;y++)
3283                         {
3284                                 x = 1;
3285                                 pixelband = 0;
3286                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3287                                 highpixel = highpixels + 4*index;
3288                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3289                                 {
3290                                         // only convert pixels that were hit by photons
3291                                         if (VectorLength2(highpixel))
3292                                         {
3293                                                 // process all of the pixelbands for this pixel
3294                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3295                                                 {
3296                                                         // time to have fun with IEEE 754 bit hacking...
3297                                                         union {
3298                                                                 float f[4];
3299                                                                 unsigned int raw[4];
3300                                                         } u;
3301                                                         pixelrgba16f = pixelsrgba16f + 4*bandindex;
3302                                                         bandpixel = highpixels + 4*bandindex;
3303                                                         VectorCopy4(bandpixel, u.f);
3304                                                         VectorCopy4(u.raw, c);
3305                                                         // this math supports negative numbers, snaps denormals to zero
3306                                                         //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3307                                                         //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3308                                                         //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3309                                                         //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3310                                                         // this math does not support negative
3311                                                         pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3312                                                         pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3313                                                         pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3314                                                         pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3315                                                 }
3316                                         }
3317                                 }
3318                         }
3319                 }
3320
3321                 if (!r_shadow_bouncegrid_state.createtexture)
3322                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3323                 else
3324                         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);
3325                 break;
3326         case 2:
3327                 // our native format happens to match, so this is easy.
3328                 pixelsrgba32f = highpixels;
3329
3330                 if (!r_shadow_bouncegrid_state.createtexture)
3331                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3332                 else
3333                         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);
3334                 break;
3335         }
3336
3337         r_shadow_bouncegrid_state.lastupdatetime = realtime;
3338 }
3339
3340 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3341 {
3342         vec3_t bouncerandom[10];
3343         dlight_t *light;
3344         int bouncecount;
3345         int hitsupercontentsmask;
3346         int skipsupercontentsmask;
3347         int skipmaterialflagsmask;
3348         int maxbounce;
3349         int shootparticles;
3350         int shotparticles;
3351         float bounceminimumintensity2;
3352         trace_t cliptrace;
3353         //trace_t cliptrace2;
3354         //trace_t cliptrace3;
3355         unsigned int lightindex;
3356         unsigned int seed;
3357         randomseed_t randomseed;
3358         vec3_t shotcolor;
3359         vec3_t baseshotcolor;
3360         vec3_t surfcolor;
3361         vec3_t clipend;
3362         vec3_t clipstart;
3363         vec3_t clipdiff;
3364         vec_t radius;
3365         vec_t distancetraveled;
3366         vec_t s;
3367         rtlight_t *rtlight;
3368
3369         // compute a seed for the unstable random modes
3370         Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3371         seed = realtime * 1000.0;
3372
3373         r_shadow_bouncegrid_state.numsplatpaths = 0;
3374
3375         // figure out what we want to interact with
3376         if (settings.hitmodels)
3377                 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3378         else
3379                 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3380         skipsupercontentsmask = 0;
3381         skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
3382         maxbounce = settings.maxbounce;
3383
3384         for (lightindex = 0;lightindex < range2;lightindex++)
3385         {
3386                 if (lightindex < range)
3387                 {
3388                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3389                         if (!light)
3390                                 continue;
3391                         rtlight = &light->rtlight;
3392                 }
3393                 else
3394                         rtlight = r_refdef.scene.lights[lightindex - range];
3395                 // note that this code used to keep track of residual photons and
3396                 // distribute them evenly to achieve exactly a desired photon count,
3397                 // but that caused unwanted flickering in dynamic mode
3398                 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3399                 // skip if we won't be shooting any photons
3400                 if (!shootparticles)
3401                         continue;
3402                 radius = rtlight->radius * settings.lightradiusscale;
3403                 //s = settings.particleintensity / shootparticles;
3404                 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3405                 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3406                 if (VectorLength2(baseshotcolor) <= 0.0f)
3407                         continue;
3408                 r_refdef.stats[r_stat_bouncegrid_lights]++;
3409                 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3410                 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3411                 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3412
3413                 // for seeded random we start the RNG with the position of the light
3414                 if (settings.rng_seed >= 0)
3415                 {
3416                         union
3417                         {
3418                                 unsigned int i[4];
3419                                 float f[4];
3420                         }
3421                         u;
3422                         u.f[0] = rtlight->shadoworigin[0];
3423                         u.f[1] = rtlight->shadoworigin[1];
3424                         u.f[2] = rtlight->shadoworigin[2];
3425                         u.f[3] = 1;
3426                         switch (settings.rng_type)
3427                         {
3428                         default:
3429                         case 0:
3430                                 // we have to shift the seed provided by the user because the result must be odd
3431                                 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3432                                 break;
3433                         case 1:
3434                                 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3435                                 break;
3436                         }
3437                 }
3438
3439                 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3440                 {
3441                         VectorCopy(baseshotcolor, shotcolor);
3442                         VectorCopy(rtlight->shadoworigin, clipstart);
3443                         switch (settings.rng_type)
3444                         {
3445                         default:
3446                         case 0:
3447                                 VectorLehmerRandom(&randomseed, clipend);
3448                                 if (settings.bounceanglediffuse)
3449                                 {
3450                                         // we want random to be stable, so we still have to do all the random we would have done
3451                                         for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3452                                                 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3453                                 }
3454                                 break;
3455                         case 1:
3456                                 VectorCheeseRandom(seed, clipend);
3457                                 if (settings.bounceanglediffuse)
3458                                 {
3459                                         // we want random to be stable, so we still have to do all the random we would have done
3460                                         for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3461                                                 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3462                                 }
3463                                 break;
3464                         }
3465
3466                         // we want a uniform distribution spherically, not merely within the sphere
3467                         if (settings.normalizevectors)
3468                                 VectorNormalize(clipend);
3469
3470                         VectorMA(clipstart, radius, clipend, clipend);
3471                         distancetraveled = 0.0f;
3472                         for (bouncecount = 0;;bouncecount++)
3473                         {
3474                                 r_refdef.stats[r_stat_bouncegrid_traces]++;
3475                                 rtlight->bouncegrid_traces++;
3476                                 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3477                                 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3478                                 if (settings.staticmode || settings.rng_seed < 0)
3479                                 {
3480                                         // static mode fires a LOT of rays but none of them are identical, so they are not cached
3481                                         // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3482                                         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);
3483                                 }
3484                                 else
3485                                 {
3486                                         // dynamic mode fires many rays and most will match the cache from the previous frame
3487                                         cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
3488                                 }
3489                                 if (bouncecount > 0 || settings.includedirectlighting)
3490                                 {
3491                                         vec3_t hitpos;
3492                                         VectorCopy(cliptrace.endpos, hitpos);
3493                                         R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3494                                 }
3495                                 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3496                                 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3497                                 if (rtlight->bouncegrid_effectiveradius < s)
3498                                         rtlight->bouncegrid_effectiveradius = s;
3499                                 if (cliptrace.fraction >= 1.0f)
3500                                         break;
3501                                 r_refdef.stats[r_stat_bouncegrid_hits]++;
3502                                 rtlight->bouncegrid_hits++;
3503                                 if (bouncecount >= maxbounce)
3504                                         break;
3505                                 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3506                                 // also clamp the resulting color to never add energy, even if the user requests extreme values
3507                                 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3508                                         VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3509                                 else
3510                                         VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3511                                 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3512                                 surfcolor[0] = min(surfcolor[0], 1.0f);
3513                                 surfcolor[1] = min(surfcolor[1], 1.0f);
3514                                 surfcolor[2] = min(surfcolor[2], 1.0f);
3515                                 VectorMultiply(shotcolor, surfcolor, shotcolor);
3516                                 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3517                                         break;
3518                                 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3519                                 if (settings.bounceanglediffuse)
3520                                 {
3521                                         // random direction, primarily along plane normal
3522                                         s = VectorDistance(cliptrace.endpos, clipend);
3523                                         VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3524                                         VectorNormalize(clipend);
3525                                         VectorScale(clipend, s, clipend);
3526                                 }
3527                                 else
3528                                 {
3529                                         // reflect the remaining portion of the line across plane normal
3530                                         VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3531                                         VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3532                                 }
3533                                 // calculate the new line start and end
3534                                 VectorCopy(cliptrace.endpos, clipstart);
3535                                 VectorAdd(clipstart, clipend, clipend);
3536                         }
3537                 }
3538         }
3539 }
3540
3541 void R_Shadow_UpdateBounceGridTexture(void)
3542 {
3543         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3544         r_shadow_bouncegrid_settings_t settings;
3545         qboolean enable = false;
3546         qboolean settingschanged;
3547         unsigned int range; // number of world lights
3548         unsigned int range1; // number of dynamic lights (or zero if disabled)
3549         unsigned int range2; // range+range1
3550
3551         enable = R_Shadow_BounceGrid_CheckEnable(flag);
3552         
3553         R_Shadow_BounceGrid_GenerateSettings(&settings);
3554         
3555         // changing intensity does not require an update
3556         r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3557
3558         settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3559
3560         // when settings change, we free everything as it is just simpler that way.
3561         if (settingschanged || !enable)
3562         {
3563                 // not enabled, make sure we free anything we don't need anymore.
3564                 if (r_shadow_bouncegrid_state.texture)
3565                 {
3566                         R_FreeTexture(r_shadow_bouncegrid_state.texture);
3567                         r_shadow_bouncegrid_state.texture = NULL;
3568                 }
3569                 r_shadow_bouncegrid_state.highpixels = NULL;
3570                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3571                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3572                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3573                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3574                 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3575                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3576                 r_shadow_bouncegrid_state.numpixels = 0;
3577                 r_shadow_bouncegrid_state.directional = false;
3578
3579                 if (!enable)
3580                         return;
3581         }
3582
3583         // if all the settings seem identical to the previous update, return
3584         if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3585                 return;
3586
3587         // store the new settings
3588         r_shadow_bouncegrid_state.settings = settings;
3589
3590         R_Shadow_BounceGrid_UpdateSpacing();
3591
3592         // get the range of light numbers we'll be looping over:
3593         // range = static lights
3594         // range1 = dynamic lights (optional)
3595         // range2 = range + range1
3596         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3597         range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3598         range2 = range + range1;
3599
3600         // calculate weighting factors for distributing photons among the lights
3601         R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3602
3603         // trace the photons from lights and accumulate illumination
3604         R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3605
3606         // clear the texture
3607         R_Shadow_BounceGrid_ClearPixels();
3608         
3609         // accumulate the light splatting into texture
3610         R_Shadow_BounceGrid_PerformSplats();
3611
3612         // apply a mild blur filter to the texture
3613         R_Shadow_BounceGrid_BlurPixels();
3614
3615         // convert the pixels to lower precision and upload the texture
3616         R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3617
3618         // after we compute the static lighting we don't need to keep the highpixels array around
3619         if (settings.staticmode)
3620         {
3621                 r_shadow_bouncegrid_state.highpixels = NULL;
3622                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3623                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3624                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3625                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3626                 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3627                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3628         }
3629 }
3630
3631 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3632 {
3633         R_Shadow_RenderMode_Reset();
3634         GL_BlendFunc(GL_ONE, GL_ONE);
3635         GL_DepthRange(0, 1);
3636         GL_DepthTest(r_showshadowvolumes.integer < 2);
3637         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3638         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3639         GL_CullFace(GL_NONE);
3640         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3641 }
3642
3643 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3644 {
3645         R_Shadow_RenderMode_Reset();
3646         GL_BlendFunc(GL_ONE, GL_ONE);
3647         GL_DepthRange(0, 1);
3648         GL_DepthTest(r_showlighting.integer < 2);
3649         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3650         if (!transparent)
3651                 GL_DepthFunc(GL_EQUAL);
3652         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3653         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3654 }
3655
3656 void R_Shadow_RenderMode_End(void)
3657 {
3658         R_Shadow_RenderMode_Reset();
3659         R_Shadow_RenderMode_ActiveLight(NULL);
3660         GL_DepthMask(true);
3661         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3662         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3663 }
3664
3665 int bboxedges[12][2] =
3666 {
3667         // top
3668         {0, 1}, // +X
3669         {0, 2}, // +Y
3670         {1, 3}, // Y, +X
3671         {2, 3}, // X, +Y
3672         // bottom
3673         {4, 5}, // +X
3674         {4, 6}, // +Y
3675         {5, 7}, // Y, +X
3676         {6, 7}, // X, +Y
3677         // verticals
3678         {0, 4}, // +Z
3679         {1, 5}, // X, +Z
3680         {2, 6}, // Y, +Z
3681         {3, 7}, // XY, +Z
3682 };
3683
3684 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3685 {
3686         if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3687         {
3688                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3689                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3690                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3691                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3692                 return false;
3693         }
3694         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3695                 return true; // invisible
3696         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3697         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3698         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3699         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3700                 r_refdef.stats[r_stat_lights_scissored]++;
3701         return false;
3702 }
3703
3704 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3705 {
3706         int i;
3707         const float *vertex3f;
3708         const float *normal3f;
3709         float *color4f;
3710         float dist, dot, distintensity, shadeintensity, v[3], n[3];
3711         switch (r_shadow_rendermode)
3712         {
3713         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3714         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3715                 if (VectorLength2(diffusecolor) > 0)
3716                 {
3717                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3718                         {
3719                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3720                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3721                                 if ((dot = DotProduct(n, v)) < 0)
3722                                 {
3723                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3724                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3725                                 }
3726                                 else
3727                                         VectorCopy(ambientcolor, color4f);
3728                                 if (r_refdef.fogenabled)
3729                                 {
3730                                         float f;
3731                                         f = RSurf_FogVertex(vertex3f);
3732                                         VectorScale(color4f, f, color4f);
3733                                 }
3734                                 color4f[3] = 1;
3735                         }
3736                 }
3737                 else
3738                 {
3739                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3740                         {
3741                                 VectorCopy(ambientcolor, color4f);
3742                                 if (r_refdef.fogenabled)
3743                                 {
3744                                         float f;
3745                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3746                                         f = RSurf_FogVertex(vertex3f);
3747                                         VectorScale(color4f + 4*i, f, color4f);
3748                                 }
3749                                 color4f[3] = 1;
3750                         }
3751                 }
3752                 break;
3753         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3754                 if (VectorLength2(diffusecolor) > 0)
3755                 {
3756                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3757                         {
3758                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3759                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3760                                 {
3761                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3762                                         if ((dot = DotProduct(n, v)) < 0)
3763                                         {
3764                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3765                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3766                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3767                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3768                                         }
3769                                         else
3770                                         {
3771                                                 color4f[0] = ambientcolor[0] * distintensity;
3772                                                 color4f[1] = ambientcolor[1] * distintensity;
3773                                                 color4f[2] = ambientcolor[2] * distintensity;
3774                                         }
3775                                         if (r_refdef.fogenabled)
3776                                         {
3777                                                 float f;
3778                                                 f = RSurf_FogVertex(vertex3f);
3779                                                 VectorScale(color4f, f, color4f);
3780                                         }
3781                                 }
3782                                 else
3783                                         VectorClear(color4f);
3784                                 color4f[3] = 1;
3785                         }
3786                 }
3787                 else
3788                 {
3789                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3790                         {
3791                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3792                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3793                                 {
3794                                         color4f[0] = ambientcolor[0] * distintensity;
3795                                         color4f[1] = ambientcolor[1] * distintensity;
3796                                         color4f[2] = ambientcolor[2] * distintensity;
3797                                         if (r_refdef.fogenabled)
3798                                         {
3799                                                 float f;
3800                                                 f = RSurf_FogVertex(vertex3f);
3801                                                 VectorScale(color4f, f, color4f);
3802                                         }
3803                                 }
3804                                 else
3805                                         VectorClear(color4f);
3806                                 color4f[3] = 1;
3807                         }
3808                 }
3809                 break;
3810         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3811                 if (VectorLength2(diffusecolor) > 0)
3812                 {
3813                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3814                         {
3815                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3816                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3817                                 {
3818                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3819                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3820                                         if ((dot = DotProduct(n, v)) < 0)
3821                                         {
3822                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3823                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3824                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3825                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3826                                         }
3827                                         else
3828                                         {
3829                                                 color4f[0] = ambientcolor[0] * distintensity;
3830                                                 color4f[1] = ambientcolor[1] * distintensity;
3831                                                 color4f[2] = ambientcolor[2] * distintensity;
3832                                         }
3833                                         if (r_refdef.fogenabled)
3834                                         {
3835                                                 float f;
3836                                                 f = RSurf_FogVertex(vertex3f);
3837                                                 VectorScale(color4f, f, color4f);
3838                                         }
3839                                 }
3840                                 else
3841                                         VectorClear(color4f);
3842                                 color4f[3] = 1;
3843                         }
3844                 }
3845                 else
3846                 {
3847                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3848                         {
3849                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3850                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3851                                 {
3852                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3853                                         color4f[0] = ambientcolor[0] * distintensity;
3854                                         color4f[1] = ambientcolor[1] * distintensity;
3855                                         color4f[2] = ambientcolor[2] * distintensity;
3856                                         if (r_refdef.fogenabled)
3857                                         {
3858                                                 float f;
3859                                                 f = RSurf_FogVertex(vertex3f);
3860                                                 VectorScale(color4f, f, color4f);
3861                                         }
3862                                 }
3863                                 else
3864                                         VectorClear(color4f);
3865                                 color4f[3] = 1;
3866                         }
3867                 }
3868                 break;
3869         default:
3870                 break;
3871         }
3872 }
3873
3874 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3875 {
3876         // used to display how many times a surface is lit for level design purposes
3877         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3878         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3879         RSurf_DrawBatch();
3880 }
3881
3882 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3883 {
3884         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3885         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3886         RSurf_DrawBatch();
3887 }
3888
3889 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3890 {
3891         int renders;
3892         int i;
3893         int stop;
3894         int newfirstvertex;
3895         int newlastvertex;
3896         int newnumtriangles;
3897         int *newe;
3898         const int *e;
3899         float *c;
3900         int maxtriangles = 1024;
3901         int newelements[1024*3];
3902         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3903         for (renders = 0;renders < 4;renders++)
3904         {
3905                 stop = true;
3906                 newfirstvertex = 0;
3907                 newlastvertex = 0;
3908                 newnumtriangles = 0;
3909                 newe = newelements;
3910                 // due to low fillrate on the cards this vertex lighting path is
3911                 // designed for, we manually cull all triangles that do not
3912                 // contain a lit vertex
3913                 // this builds batches of triangles from multiple surfaces and
3914                 // renders them at once
3915                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3916                 {
3917                         if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3918                         {
3919                                 if (newnumtriangles)
3920                                 {
3921                                         newfirstvertex = min(newfirstvertex, e[0]);
3922                                         newlastvertex  = max(newlastvertex, e[0]);
3923                                 }
3924                                 else
3925                                 {
3926                                         newfirstvertex = e[0];
3927                                         newlastvertex = e[0];
3928                                 }
3929                                 newfirstvertex = min(newfirstvertex, e[1]);
3930                                 newlastvertex  = max(newlastvertex, e[1]);
3931                                 newfirstvertex = min(newfirstvertex, e[2]);
3932                                 newlastvertex  = max(newlastvertex, e[2]);
3933                                 newe[0] = e[0];
3934                                 newe[1] = e[1];
3935                                 newe[2] = e[2];
3936                                 newnumtriangles++;
3937                                 newe += 3;
3938                                 if (newnumtriangles >= maxtriangles)
3939                                 {
3940                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3941                                         newnumtriangles = 0;
3942                                         newe = newelements;
3943                                         stop = false;
3944                                 }
3945                         }
3946                 }
3947                 if (newnumtriangles >= 1)
3948                 {
3949                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3950                         stop = false;
3951                 }
3952                 // if we couldn't find any lit triangles, exit early
3953                 if (stop)
3954                         break;
3955                 // now reduce the intensity for the next overbright pass
3956                 // we have to clamp to 0 here incase the drivers have improper
3957                 // handling of negative colors
3958                 // (some old drivers even have improper handling of >1 color)
3959                 stop = true;
3960                 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3961                 {
3962                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3963                         {
3964                                 c[0] = max(0, c[0] - 1);
3965                                 c[1] = max(0, c[1] - 1);
3966                                 c[2] = max(0, c[2] - 1);
3967                                 stop = false;
3968                         }
3969                         else
3970                                 VectorClear(c);
3971                 }
3972                 // another check...
3973                 if (stop)
3974                         break;
3975         }
3976 }
3977
3978 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3979 {
3980         // OpenGL 1.1 path (anything)
3981         float ambientcolorbase[3], diffusecolorbase[3];
3982         float ambientcolorpants[3], diffusecolorpants[3];
3983         float ambientcolorshirt[3], diffusecolorshirt[3];
3984         const float *surfacecolor = rsurface.texture->dlightcolor;
3985         const float *surfacepants = rsurface.colormap_pantscolor;
3986         const float *surfaceshirt = rsurface.colormap_shirtcolor;
3987         rtexture_t *basetexture = rsurface.texture->basetexture;
3988         rtexture_t *pantstexture = rsurface.texture->pantstexture;
3989         rtexture_t *shirttexture = rsurface.texture->shirttexture;
3990         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3991         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3992         ambientscale *= 2 * r_refdef.view.colorscale;
3993         diffusescale *= 2 * r_refdef.view.colorscale;
3994         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3995         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3996         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3997         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3998         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3999         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
4000         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
4001         rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
4002         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4003         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
4004         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
4005         R_Mesh_TexBind(0, basetexture);
4006         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
4007         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
4008         switch(r_shadow_rendermode)
4009         {
4010         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4011                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
4012                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4013                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4014                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4015                 break;
4016         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4017                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
4018                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
4019                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
4020                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4021                 // fall through
4022         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4023                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
4024                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4025                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4026                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4027                 break;
4028         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4029                 break;
4030         default:
4031                 break;
4032         }
4033         //R_Mesh_TexBind(0, basetexture);
4034         R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4035         if (dopants)
4036         {
4037                 R_Mesh_TexBind(0, pantstexture);
4038                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4039         }
4040         if (doshirt)
4041         {
4042                 R_Mesh_TexBind(0, shirttexture);
4043                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4044         }
4045 }
4046
4047 extern cvar_t gl_lightmaps;
4048 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4049 {
4050         float ambientscale, diffusescale, specularscale;
4051         qboolean negated;
4052         float lightcolor[3];
4053         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
4054         ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
4055         diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
4056         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
4057         if (!r_shadow_usenormalmap.integer)
4058         {
4059                 ambientscale += 1.0f * diffusescale;
4060                 diffusescale = 0;
4061                 specularscale = 0;
4062         }
4063         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
4064                 return;
4065         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
4066         if(negated)
4067         {
4068                 VectorNegate(lightcolor, lightcolor);
4069                 GL_BlendEquationSubtract(true);
4070         }
4071         RSurf_SetupDepthAndCulling();
4072         switch (r_shadow_rendermode)
4073         {
4074         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
4075                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4076                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4077                 break;
4078         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4079                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
4080                 break;
4081         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4082         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4083         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4084         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4085                 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
4086                 break;
4087         default:
4088                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4089                 break;
4090         }
4091         if(negated)
4092                 GL_BlendEquationSubtract(false);
4093 }
4094
4095 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)
4096 {
4097         matrix4x4_t tempmatrix = *matrix;
4098         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4099
4100         // if this light has been compiled before, free the associated data
4101         R_RTLight_Uncompile(rtlight);
4102
4103         // clear it completely to avoid any lingering data
4104         memset(rtlight, 0, sizeof(*rtlight));
4105
4106         // copy the properties
4107         rtlight->matrix_lighttoworld = tempmatrix;
4108         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4109         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4110         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4111         VectorCopy(color, rtlight->color);
4112         rtlight->cubemapname[0] = 0;
4113         if (cubemapname && cubemapname[0])
4114                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4115         rtlight->shadow = shadow;
4116         rtlight->corona = corona;
4117         rtlight->style = style;
4118         rtlight->isstatic = isstatic;
4119         rtlight->coronasizescale = coronasizescale;
4120         rtlight->ambientscale = ambientscale;
4121         rtlight->diffusescale = diffusescale;
4122         rtlight->specularscale = specularscale;
4123         rtlight->flags = flags;
4124
4125         // compute derived data
4126         //rtlight->cullradius = rtlight->radius;
4127         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4128         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4129         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4130         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4131         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4132         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4133         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4134 }
4135
4136 // compiles rtlight geometry
4137 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4138 void R_RTLight_Compile(rtlight_t *rtlight)
4139 {
4140         int i;
4141         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4142         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4143         entity_render_t *ent = r_refdef.scene.worldentity;
4144         dp_model_t *model = r_refdef.scene.worldmodel;
4145         unsigned char *data;
4146         shadowmesh_t *mesh;
4147
4148         // compile the light
4149         rtlight->compiled = true;
4150         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4151         rtlight->static_numleafs = 0;
4152         rtlight->static_numleafpvsbytes = 0;
4153         rtlight->static_leaflist = NULL;
4154         rtlight->static_leafpvs = NULL;
4155         rtlight->static_numsurfaces = 0;
4156         rtlight->static_surfacelist = NULL;
4157         rtlight->static_shadowmap_receivers = 0x3F;
4158         rtlight->static_shadowmap_casters = 0x3F;
4159         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4160         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4161         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4162         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4163         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4164         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4165
4166         if (model && model->GetLightInfo)
4167         {
4168                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4169                 r_shadow_compilingrtlight = rtlight;
4170                 R_FrameData_SetMark();
4171                 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);
4172                 R_FrameData_ReturnToMark();
4173                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4174                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4175                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4176                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4177                 rtlight->static_numsurfaces = numsurfaces;
4178                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4179                 rtlight->static_numleafs = numleafs;
4180                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4181                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4182                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4183                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4184                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4185                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4186                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4187                 if (rtlight->static_numsurfaces)
4188                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4189                 if (rtlight->static_numleafs)
4190                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4191                 if (rtlight->static_numleafpvsbytes)
4192                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4193                 if (rtlight->static_numshadowtrispvsbytes)
4194                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4195                 if (rtlight->static_numlighttrispvsbytes)
4196                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4197                 R_FrameData_SetMark();
4198                 switch (rtlight->shadowmode)
4199                 {
4200                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4201                         if (model->CompileShadowMap && rtlight->shadow)
4202                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4203                         break;
4204                 default:
4205                         if (model->CompileShadowVolume && rtlight->shadow)
4206                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4207                         break;
4208                 }
4209                 R_FrameData_ReturnToMark();
4210                 // now we're done compiling the rtlight
4211                 r_shadow_compilingrtlight = NULL;
4212         }
4213
4214
4215         // use smallest available cullradius - box radius or light radius
4216         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4217         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4218
4219         shadowzpasstris = 0;
4220         if (rtlight->static_meshchain_shadow_zpass)
4221                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4222                         shadowzpasstris += mesh->numtriangles;
4223
4224         shadowzfailtris = 0;
4225         if (rtlight->static_meshchain_shadow_zfail)
4226                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4227                         shadowzfailtris += mesh->numtriangles;
4228
4229         lighttris = 0;
4230         if (rtlight->static_numlighttrispvsbytes)
4231                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4232                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4233                                 lighttris++;
4234
4235         shadowtris = 0;
4236         if (rtlight->static_numshadowtrispvsbytes)
4237                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4238                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4239                                 shadowtris++;
4240
4241         if (developer_extra.integer)
4242                 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
4243 }
4244
4245 void R_RTLight_Uncompile(rtlight_t *rtlight)
4246 {
4247         if (rtlight->compiled)
4248         {
4249                 if (rtlight->static_meshchain_shadow_zpass)
4250                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4251                 rtlight->static_meshchain_shadow_zpass = NULL;
4252                 if (rtlight->static_meshchain_shadow_zfail)
4253                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4254                 rtlight->static_meshchain_shadow_zfail = NULL;
4255                 if (rtlight->static_meshchain_shadow_shadowmap)
4256                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4257                 rtlight->static_meshchain_shadow_shadowmap = NULL;
4258                 // these allocations are grouped
4259                 if (rtlight->static_surfacelist)
4260                         Mem_Free(rtlight->static_surfacelist);
4261                 rtlight->static_numleafs = 0;
4262                 rtlight->static_numleafpvsbytes = 0;
4263                 rtlight->static_leaflist = NULL;
4264                 rtlight->static_leafpvs = NULL;
4265                 rtlight->static_numsurfaces = 0;
4266                 rtlight->static_surfacelist = NULL;
4267                 rtlight->static_numshadowtrispvsbytes = 0;
4268                 rtlight->static_shadowtrispvs = NULL;
4269                 rtlight->static_numlighttrispvsbytes = 0;
4270                 rtlight->static_lighttrispvs = NULL;
4271                 rtlight->compiled = false;
4272         }
4273 }
4274
4275 void R_Shadow_UncompileWorldLights(void)
4276 {
4277         size_t lightindex;
4278         dlight_t *light;
4279         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4280         for (lightindex = 0;lightindex < range;lightindex++)
4281         {
4282                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4283                 if (!light)
4284                         continue;
4285                 R_RTLight_Uncompile(&light->rtlight);
4286         }
4287 }
4288
4289 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4290 {
4291         int i, j;
4292         mplane_t plane;
4293         // reset the count of frustum planes
4294         // see rtlight->cached_frustumplanes definition for how much this array
4295         // can hold
4296         rtlight->cached_numfrustumplanes = 0;
4297
4298         if (r_trippy.integer)
4299                 return;
4300
4301         // haven't implemented a culling path for ortho rendering
4302         if (!r_refdef.view.useperspective)
4303         {
4304                 // check if the light is on screen and copy the 4 planes if it is
4305                 for (i = 0;i < 4;i++)
4306                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4307                                 break;
4308                 if (i == 4)
4309                         for (i = 0;i < 4;i++)
4310                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4311                 return;
4312         }
4313
4314 #if 1
4315         // generate a deformed frustum that includes the light origin, this is
4316         // used to cull shadow casting surfaces that can not possibly cast a
4317         // shadow onto the visible light-receiving surfaces, which can be a
4318         // performance gain
4319         //
4320         // if the light origin is onscreen the result will be 4 planes exactly
4321         // if the light origin is offscreen on only one axis the result will
4322         // be exactly 5 planes (split-side case)
4323         // if the light origin is offscreen on two axes the result will be
4324         // exactly 4 planes (stretched corner case)
4325         for (i = 0;i < 4;i++)
4326         {
4327                 // quickly reject standard frustum planes that put the light
4328                 // origin outside the frustum
4329                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4330                         continue;
4331                 // copy the plane
4332                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4333         }
4334         // if all the standard frustum planes were accepted, the light is onscreen
4335         // otherwise we need to generate some more planes below...
4336         if (rtlight->cached_numfrustumplanes < 4)
4337         {
4338                 // at least one of the stock frustum planes failed, so we need to
4339                 // create one or two custom planes to enclose the light origin
4340                 for (i = 0;i < 4;i++)
4341                 {
4342                         // create a plane using the view origin and light origin, and a
4343                         // single point from the frustum corner set
4344                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4345                         VectorNormalize(plane.normal);
4346                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4347                         // see if this plane is backwards and flip it if so
4348                         for (j = 0;j < 4;j++)
4349                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4350                                         break;
4351                         if (j < 4)
4352                         {
4353                                 VectorNegate(plane.normal, plane.normal);
4354                                 plane.dist *= -1;
4355                                 // flipped plane, test again to see if it is now valid
4356                                 for (j = 0;j < 4;j++)
4357                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4358                                                 break;
4359                                 // if the plane is still not valid, then it is dividing the
4360                                 // frustum and has to be rejected
4361                                 if (j < 4)
4362                                         continue;
4363                         }
4364                         // we have created a valid plane, compute extra info
4365                         PlaneClassify(&plane);
4366                         // copy the plane
4367                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4368 #if 1
4369                         // if we've found 5 frustum planes then we have constructed a
4370                         // proper split-side case and do not need to keep searching for
4371                         // planes to enclose the light origin
4372                         if (rtlight->cached_numfrustumplanes == 5)
4373                                 break;
4374 #endif
4375                 }
4376         }
4377 #endif
4378
4379 #if 0
4380         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4381         {
4382                 plane = rtlight->cached_frustumplanes[i];
4383                 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));
4384         }
4385 #endif
4386
4387 #if 0
4388         // now add the light-space box planes if the light box is rotated, as any
4389         // caster outside the oriented light box is irrelevant (even if it passed
4390         // the worldspace light box, which is axial)
4391         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4392         {
4393                 for (i = 0;i < 6;i++)
4394                 {
4395                         vec3_t v;
4396                         VectorClear(v);
4397                         v[i >> 1] = (i & 1) ? -1 : 1;
4398                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4399                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4400                         plane.dist = VectorNormalizeLength(plane.normal);
4401                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4402                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4403                 }
4404         }
4405 #endif
4406
4407 #if 0
4408         // add the world-space reduced box planes
4409         for (i = 0;i < 6;i++)
4410         {
4411                 VectorClear(plane.normal);
4412                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4413                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4414                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4415         }
4416 #endif
4417
4418 #if 0
4419         {
4420         int j, oldnum;
4421         vec3_t points[8];
4422         vec_t bestdist;
4423         // reduce all plane distances to tightly fit the rtlight cull box, which
4424         // is in worldspace
4425         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4426         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4427         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4428         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4429         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4430         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4431         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4432         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4433         oldnum = rtlight->cached_numfrustumplanes;
4434         rtlight->cached_numfrustumplanes = 0;
4435         for (j = 0;j < oldnum;j++)
4436         {
4437                 // find the nearest point on the box to this plane
4438                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4439                 for (i = 1;i < 8;i++)
4440                 {
4441                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4442                         if (bestdist > dist)
4443                                 bestdist = dist;
4444                 }
4445                 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);
4446                 // if the nearest point is near or behind the plane, we want this
4447                 // plane, otherwise the plane is useless as it won't cull anything
4448                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4449                 {
4450                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
4451                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4452                 }
4453         }
4454         }
4455 #endif
4456 }
4457
4458 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4459 {
4460         shadowmesh_t *mesh;
4461
4462         RSurf_ActiveWorldEntity();
4463
4464         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4465         {
4466                 CHECKGLERROR
4467                 GL_CullFace(GL_NONE);
4468                 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4469                 for (;mesh;mesh = mesh->next)
4470                 {
4471                         if (!mesh->sidetotals[r_shadow_shadowmapside])
4472                                 continue;
4473                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4474                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4475                         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);
4476                 }
4477                 CHECKGLERROR
4478         }
4479         else if (r_refdef.scene.worldentity->model)
4480                 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);
4481
4482         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4483 }
4484
4485 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4486 {
4487         qboolean zpass = false;
4488         shadowmesh_t *mesh;
4489         int t, tend;
4490         int surfacelistindex;
4491         msurface_t *surface;
4492
4493         // if triangle neighbors are disabled, shadowvolumes are disabled
4494         if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4495                 return;
4496
4497         RSurf_ActiveWorldEntity();
4498
4499         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4500         {
4501                 CHECKGLERROR
4502                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4503                 {
4504                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4505                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4506                 }
4507                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4508                 for (;mesh;mesh = mesh->next)
4509                 {
4510                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4511                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4512                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4513                         {
4514                                 // increment stencil if frontface is infront of depthbuffer
4515                                 GL_CullFace(r_refdef.view.cullface_back);
4516                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4517                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
4518                                 // decrement stencil if backface is infront of depthbuffer
4519                                 GL_CullFace(r_refdef.view.cullface_front);
4520                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4521                         }
4522                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4523                         {
4524                                 // decrement stencil if backface is behind depthbuffer
4525                                 GL_CullFace(r_refdef.view.cullface_front);
4526                                 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4527                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
4528                                 // increment stencil if frontface is behind depthbuffer
4529                                 GL_CullFace(r_refdef.view.cullface_back);
4530                                 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4531                         }
4532                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
4533                 }
4534                 CHECKGLERROR
4535         }
4536         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4537         {
4538                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4539                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4540                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4541                 {
4542                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4543                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4544                                 if (CHECKPVSBIT(trispvs, t))
4545                                         shadowmarklist[numshadowmark++] = t;
4546                 }
4547                 R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4548         }
4549         else if (numsurfaces)
4550         {
4551                 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
4552         }
4553
4554         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4555 }
4556
4557 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4558 {
4559         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4560         vec_t relativeshadowradius;
4561         RSurf_ActiveModelEntity(ent, false, false, false);
4562         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4563         // we need to re-init the shader for each entity because the matrix changed
4564         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4565         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4566         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4567         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4568         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4569         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4570         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4571         switch (r_shadow_rendermode)
4572         {
4573         case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4574                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4575                 break;
4576         default:
4577                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4578                 break;
4579         }
4580         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4581 }
4582
4583 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4584 {
4585         // set up properties for rendering light onto this entity
4586         RSurf_ActiveModelEntity(ent, true, true, false);
4587         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4588         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4589         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4590         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4591 }
4592
4593 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4594 {
4595         if (!r_refdef.scene.worldmodel->DrawLight)
4596                 return;
4597
4598         // set up properties for rendering light onto this entity
4599         RSurf_ActiveWorldEntity();
4600         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4601         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4602         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4603         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4604
4605         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4606
4607         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4608 }
4609
4610 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4611 {
4612         dp_model_t *model = ent->model;
4613         if (!model->DrawLight)
4614                 return;
4615
4616         R_Shadow_SetupEntityLight(ent);
4617
4618         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4619
4620         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4621 }
4622
4623 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4624 {
4625         int i;
4626         float f;
4627         int numleafs, numsurfaces;
4628         int *leaflist, *surfacelist;
4629         unsigned char *leafpvs;
4630         unsigned char *shadowtrispvs;
4631         unsigned char *lighttrispvs;
4632         //unsigned char *surfacesides;
4633         int numlightentities;
4634         int numlightentities_noselfshadow;
4635         int numshadowentities;
4636         int numshadowentities_noselfshadow;
4637         // FIXME: bounds check lightentities and shadowentities, etc.
4638         static entity_render_t *lightentities[MAX_EDICTS];
4639         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4640         static entity_render_t *shadowentities[MAX_EDICTS];
4641         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4642         qboolean nolight;
4643         qboolean castshadows;
4644
4645         rtlight->draw = false;
4646         rtlight->cached_numlightentities = 0;
4647         rtlight->cached_numlightentities_noselfshadow = 0;
4648         rtlight->cached_numshadowentities = 0;
4649         rtlight->cached_numshadowentities_noselfshadow = 0;
4650         rtlight->cached_numsurfaces = 0;
4651         rtlight->cached_lightentities = NULL;
4652         rtlight->cached_lightentities_noselfshadow = NULL;
4653         rtlight->cached_shadowentities = NULL;
4654         rtlight->cached_shadowentities_noselfshadow = NULL;
4655         rtlight->cached_shadowtrispvs = NULL;
4656         rtlight->cached_lighttrispvs = NULL;
4657         rtlight->cached_surfacelist = NULL;
4658         rtlight->shadowmapsidesize = 0;
4659
4660         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4661         // skip lights that are basically invisible (color 0 0 0)
4662         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4663
4664         // loading is done before visibility checks because loading should happen
4665         // all at once at the start of a level, not when it stalls gameplay.
4666         // (especially important to benchmarks)
4667         // compile light
4668         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4669         {
4670                 if (rtlight->compiled)
4671                         R_RTLight_Uncompile(rtlight);
4672                 R_RTLight_Compile(rtlight);
4673         }
4674
4675         // load cubemap
4676         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4677
4678         // look up the light style value at this time
4679         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4680         VectorScale(rtlight->color, f, rtlight->currentcolor);
4681         /*
4682         if (rtlight->selected)
4683         {
4684                 f = 2 + sin(realtime * M_PI * 4.0);
4685                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4686         }
4687         */
4688
4689         // skip if lightstyle is currently off
4690         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4691                 return;
4692
4693         // skip processing on corona-only lights
4694         if (nolight)
4695                 return;
4696
4697         // skip if the light box is not touching any visible leafs
4698         if (r_shadow_culllights_pvs.integer
4699                 && r_refdef.scene.worldmodel
4700                 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
4701                 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
4702                 return;
4703
4704         // skip if the light box is not visible to traceline
4705         if (r_shadow_culllights_trace.integer)
4706         {
4707                 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_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
4708                         rtlight->trace_timer = realtime;
4709                 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
4710                         return;
4711         }
4712
4713         // skip if the light box is off screen
4714         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4715                 return;
4716
4717         // in the typical case this will be quickly replaced by GetLightInfo
4718         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4719         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4720
4721         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4722
4723         // 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
4724         if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4725                 return;
4726
4727         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4728         {
4729                 // compiled light, world available and can receive realtime lighting
4730                 // retrieve leaf information
4731                 numleafs = rtlight->static_numleafs;
4732                 leaflist = rtlight->static_leaflist;
4733                 leafpvs = rtlight->static_leafpvs;
4734                 numsurfaces = rtlight->static_numsurfaces;
4735                 surfacelist = rtlight->static_surfacelist;
4736                 //surfacesides = NULL;
4737                 shadowtrispvs = rtlight->static_shadowtrispvs;
4738                 lighttrispvs = rtlight->static_lighttrispvs;
4739         }
4740         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4741         {
4742                 // dynamic light, world available and can receive realtime lighting
4743                 // calculate lit surfaces and leafs
4744                 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);
4745                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4746                 leaflist = r_shadow_buffer_leaflist;
4747                 leafpvs = r_shadow_buffer_leafpvs;
4748                 surfacelist = r_shadow_buffer_surfacelist;
4749                 //surfacesides = r_shadow_buffer_surfacesides;
4750                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4751                 lighttrispvs = r_shadow_buffer_lighttrispvs;
4752                 // if the reduced leaf bounds are offscreen, skip it
4753                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4754                         return;
4755         }
4756         else
4757         {
4758                 // no world
4759                 numleafs = 0;
4760                 leaflist = NULL;
4761                 leafpvs = NULL;
4762                 numsurfaces = 0;
4763                 surfacelist = NULL;
4764                 //surfacesides = NULL;
4765                 shadowtrispvs = NULL;
4766                 lighttrispvs = NULL;
4767         }
4768         // check if light is illuminating any visible leafs
4769         if (numleafs)
4770         {
4771                 for (i = 0; i < numleafs; i++)
4772                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4773                                 break;
4774                 if (i == numleafs)
4775                         return;
4776         }
4777
4778         // make a list of lit entities and shadow casting entities
4779         numlightentities = 0;
4780         numlightentities_noselfshadow = 0;
4781         numshadowentities = 0;
4782         numshadowentities_noselfshadow = 0;
4783
4784         // add dynamic entities that are lit by the light
4785         for (i = 0; i < r_refdef.scene.numentities; i++)
4786         {
4787                 dp_model_t *model;
4788                 entity_render_t *ent = r_refdef.scene.entities[i];
4789                 vec3_t org;
4790                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4791                         continue;
4792                 // skip the object entirely if it is not within the valid
4793                 // shadow-casting region (which includes the lit region)
4794                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4795                         continue;
4796                 if (!(model = ent->model))
4797                         continue;
4798                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4799                 {
4800                         // this entity wants to receive light, is visible, and is
4801                         // inside the light box
4802                         // TODO: check if the surfaces in the model can receive light
4803                         // so now check if it's in a leaf seen by the light
4804                         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))
4805                                 continue;
4806                         if (ent->flags & RENDER_NOSELFSHADOW)
4807                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4808                         else
4809                                 lightentities[numlightentities++] = ent;
4810                         // since it is lit, it probably also casts a shadow...
4811                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4812                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4813                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4814                         {
4815                                 // note: exterior models without the RENDER_NOSELFSHADOW
4816                                 // flag still create a RENDER_NOSELFSHADOW shadow but
4817                                 // are lit normally, this means that they are
4818                                 // self-shadowing but do not shadow other
4819                                 // RENDER_NOSELFSHADOW entities such as the gun
4820                                 // (very weird, but keeps the player shadow off the gun)
4821                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4822                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4823                                 else
4824                                         shadowentities[numshadowentities++] = ent;
4825                         }
4826                 }
4827                 else if (ent->flags & RENDER_SHADOW)
4828                 {
4829                         // this entity is not receiving light, but may still need to
4830                         // cast a shadow...
4831                         // TODO: check if the surfaces in the model can cast shadow
4832                         // now check if it is in a leaf seen by the light
4833                         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))
4834                                 continue;
4835                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4836                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4837                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4838                         {
4839                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4840                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4841                                 else
4842                                         shadowentities[numshadowentities++] = ent;
4843                         }
4844                 }
4845         }
4846
4847         // return if there's nothing at all to light
4848         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4849                 return;
4850
4851         // count this light in the r_speeds
4852         r_refdef.stats[r_stat_lights]++;
4853
4854         // flag it as worth drawing later
4855         rtlight->draw = true;
4856
4857         // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4858         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4859         if (!castshadows)
4860                 numshadowentities = numshadowentities_noselfshadow = 0;
4861         rtlight->castshadows = castshadows;
4862
4863         // cache all the animated entities that cast a shadow but are not visible
4864         for (i = 0; i < numshadowentities; i++)
4865                 R_AnimCache_GetEntity(shadowentities[i], false, false);
4866         for (i = 0; i < numshadowentities_noselfshadow; i++)
4867                 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4868
4869         // 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)
4870         if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4871         {
4872                 for (i = 0; i < numshadowentities_noselfshadow; i++)
4873                         shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4874                 numshadowentities_noselfshadow = 0;
4875         }
4876
4877         // we can convert noselfshadow to regular if there are no casters of that type
4878         if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4879         {
4880                 for (i = 0; i < numlightentities_noselfshadow; i++)
4881                         lightentities[numlightentities++] = lightentities_noselfshadow[i];
4882                 numlightentities_noselfshadow = 0;
4883         }
4884
4885         // allocate some temporary memory for rendering this light later in the frame
4886         // reusable buffers need to be copied, static data can be used as-is
4887         rtlight->cached_numlightentities               = numlightentities;
4888         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
4889         rtlight->cached_numshadowentities              = numshadowentities;
4890         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4891         rtlight->cached_numsurfaces                    = numsurfaces;
4892         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4893         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4894         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4895         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4896         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4897         {
4898                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4899                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4900                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4901                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4902                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4903         }
4904         else
4905         {
4906                 // compiled light data
4907                 rtlight->cached_shadowtrispvs = shadowtrispvs;
4908                 rtlight->cached_lighttrispvs = lighttrispvs;
4909                 rtlight->cached_surfacelist = surfacelist;
4910         }
4911
4912         if (R_Shadow_ShadowMappingEnabled())
4913         {
4914                 // figure out the shadowmapping parameters for this light
4915                 vec3_t nearestpoint;
4916                 vec_t distance;
4917                 int lodlinear;
4918                 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4919                 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4920                 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4921                 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4922                 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4923                 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4924                 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4925                 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4926                 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4927         }
4928 }
4929
4930 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4931 {
4932         int i;
4933         int numsurfaces;
4934         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4935         int numlightentities;
4936         int numlightentities_noselfshadow;
4937         int numshadowentities;
4938         int numshadowentities_noselfshadow;
4939         entity_render_t **lightentities;
4940         entity_render_t **lightentities_noselfshadow;
4941         entity_render_t **shadowentities;
4942         entity_render_t **shadowentities_noselfshadow;
4943         int *surfacelist;
4944         static unsigned char entitysides[MAX_EDICTS];
4945         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4946         float borderbias;
4947         int side;
4948         int size;
4949         int castermask;
4950         int receivermask;
4951         matrix4x4_t radiustolight;
4952
4953         // check if we cached this light this frame (meaning it is worth drawing)
4954         if (!rtlight->draw || !rtlight->castshadows)
4955                 return;
4956
4957         // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4958         if (rtlight->shadowmapatlassidesize == 0)
4959         {
4960                 rtlight->castshadows = false;
4961                 return;
4962         }
4963
4964         // set up a scissor rectangle for this light
4965         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4966                 return;
4967
4968         // don't let sound skip if going slow
4969         if (r_refdef.scene.extraupdate)
4970                 S_ExtraUpdate();
4971
4972         numlightentities = rtlight->cached_numlightentities;
4973         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4974         numshadowentities = rtlight->cached_numshadowentities;
4975         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4976         numsurfaces = rtlight->cached_numsurfaces;
4977         lightentities = rtlight->cached_lightentities;
4978         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4979         shadowentities = rtlight->cached_shadowentities;
4980         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4981         shadowtrispvs = rtlight->cached_shadowtrispvs;
4982         lighttrispvs = rtlight->cached_lighttrispvs;
4983         surfacelist = rtlight->cached_surfacelist;
4984
4985         // make this the active rtlight for rendering purposes
4986         R_Shadow_RenderMode_ActiveLight(rtlight);
4987
4988         radiustolight = rtlight->matrix_worldtolight;
4989         Matrix4x4_Abs(&radiustolight);
4990
4991         size = rtlight->shadowmapatlassidesize;
4992         borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4993
4994         surfacesides = NULL;
4995         castermask = 0;
4996         receivermask = 0;
4997         if (numsurfaces)
4998         {
4999                 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
5000                 {
5001                         castermask = rtlight->static_shadowmap_casters;
5002                         receivermask = rtlight->static_shadowmap_receivers;
5003                 }
5004                 else
5005                 {
5006                         surfacesides = r_shadow_buffer_surfacesides;
5007                         for (i = 0; i < numsurfaces; i++)
5008                         {
5009                                 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
5010                                 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5011                                 castermask |= surfacesides[i];
5012                                 receivermask |= surfacesides[i];
5013                         }
5014                 }
5015         }
5016
5017         for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
5018                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5019         for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
5020                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5021
5022         receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
5023
5024         if (receivermask)
5025         {
5026                 for (i = 0; i < numshadowentities; i++)
5027                         castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5028                 for (i = 0; i < numshadowentities_noselfshadow; i++)
5029                         castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5030         }
5031
5032         // there is no need to render shadows for sides that have no receivers...
5033         castermask &= receivermask;
5034
5035         //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5036
5037         // render shadow casters into shadowmaps for this light
5038         for (side = 0; side < 6; side++)
5039         {
5040                 int bit = 1 << side;
5041                 if (castermask & bit)
5042                 {
5043                         R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
5044                         if (numsurfaces)
5045                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5046                         for (i = 0; i < numshadowentities; i++)
5047                                 if (entitysides[i] & bit)
5048                                         R_Shadow_DrawEntityShadow(shadowentities[i]);
5049                         for (i = 0; i < numshadowentities_noselfshadow; i++)
5050                                 if (entitysides_noselfshadow[i] & bit)
5051                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5052                 }
5053         }
5054         // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
5055         if (numshadowentities_noselfshadow)
5056         {
5057                 for (side = 0; side < 6; side++)
5058                 {
5059                         int bit = 1 << side;
5060                         if (castermask & bit)
5061                         {
5062                                 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
5063                                 if (numsurfaces)
5064                                         R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5065                                 for (i = 0; i < numshadowentities; i++)
5066                                         if (entitysides[i] & bit)
5067                                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
5068                         }
5069                 }
5070         }
5071 }
5072
5073 static void R_Shadow_DrawLight(rtlight_t *rtlight)
5074 {
5075         int i;
5076         int numsurfaces;
5077         unsigned char *shadowtrispvs, *lighttrispvs;
5078         int numlightentities;
5079         int numlightentities_noselfshadow;
5080         int numshadowentities;
5081         int numshadowentities_noselfshadow;
5082         entity_render_t **lightentities;
5083         entity_render_t **lightentities_noselfshadow;
5084         entity_render_t **shadowentities;
5085         entity_render_t **shadowentities_noselfshadow;
5086         int *surfacelist;
5087         qboolean castshadows;
5088
5089         // check if we cached this light this frame (meaning it is worth drawing)
5090         if (!rtlight->draw)
5091                 return;
5092
5093         // set up a scissor rectangle for this light
5094         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5095                 return;
5096
5097         // don't let sound skip if going slow
5098         if (r_refdef.scene.extraupdate)
5099                 S_ExtraUpdate();
5100
5101         numlightentities = rtlight->cached_numlightentities;
5102         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5103         numshadowentities = rtlight->cached_numshadowentities;
5104         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5105         numsurfaces = rtlight->cached_numsurfaces;
5106         lightentities = rtlight->cached_lightentities;
5107         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5108         shadowentities = rtlight->cached_shadowentities;
5109         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5110         shadowtrispvs = rtlight->cached_shadowtrispvs;
5111         lighttrispvs = rtlight->cached_lighttrispvs;
5112         surfacelist = rtlight->cached_surfacelist;
5113         castshadows = rtlight->castshadows;
5114
5115         // make this the active rtlight for rendering purposes
5116         R_Shadow_RenderMode_ActiveLight(rtlight);
5117
5118         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5119         {
5120                 // optionally draw visible shape of the shadow volumes
5121                 // for performance analysis by level designers
5122                 R_Shadow_RenderMode_VisibleShadowVolumes();
5123                 if (numsurfaces)
5124                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5125                 for (i = 0;i < numshadowentities;i++)
5126                         R_Shadow_DrawEntityShadow(shadowentities[i]);
5127                 for (i = 0;i < numshadowentities_noselfshadow;i++)
5128                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5129                 R_Shadow_RenderMode_VisibleLighting(false, false);
5130         }
5131
5132         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5133         {
5134                 // optionally draw the illuminated areas
5135                 // for performance analysis by level designers
5136                 R_Shadow_RenderMode_VisibleLighting(false, false);
5137                 if (numsurfaces)
5138                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5139                 for (i = 0;i < numlightentities;i++)
5140                         R_Shadow_DrawEntityLight(lightentities[i]);
5141                 for (i = 0;i < numlightentities_noselfshadow;i++)
5142                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5143         }
5144
5145         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5146         {
5147                 float borderbias;
5148                 int size;
5149                 float shadowmapoffsetnoselfshadow = 0;
5150                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5151                 Matrix4x4_Abs(&radiustolight);
5152
5153                 size = rtlight->shadowmapatlassidesize;
5154                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5155
5156                 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5157
5158                 if (rtlight->cached_numshadowentities_noselfshadow)
5159                         shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5160
5161                 // render lighting using the depth texture as shadowmap
5162                 // draw lighting in the unmasked areas
5163                 if (numsurfaces + numlightentities)
5164                 {
5165                         R_Shadow_RenderMode_Lighting(false, false, true, false);
5166                         // draw lighting in the unmasked areas
5167                         if (numsurfaces)
5168                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5169                         for (i = 0; i < numlightentities; i++)
5170                                 R_Shadow_DrawEntityLight(lightentities[i]);
5171                 }
5172                 // offset to the noselfshadow part of the atlas and draw those too
5173                 if (numlightentities_noselfshadow)
5174                 {
5175                         R_Shadow_RenderMode_Lighting(false, false, true, true);
5176                         for (i = 0; i < numlightentities_noselfshadow; i++)
5177                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5178                 }
5179
5180                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5181                 if (r_shadow_usingdeferredprepass)
5182                         R_Shadow_RenderMode_DrawDeferredLight(true);
5183         }
5184         else if (castshadows && vid.stencil)
5185         {
5186                 // draw stencil shadow volumes to mask off pixels that are in shadow
5187                 // so that they won't receive lighting
5188                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5189                 R_Shadow_ClearStencil();
5190
5191                 if (numsurfaces)
5192                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5193                 for (i = 0;i < numshadowentities;i++)
5194                         R_Shadow_DrawEntityShadow(shadowentities[i]);
5195
5196                 // draw lighting in the unmasked areas
5197                 R_Shadow_RenderMode_Lighting(true, false, false, false);
5198                 for (i = 0;i < numlightentities_noselfshadow;i++)
5199                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5200
5201                 for (i = 0;i < numshadowentities_noselfshadow;i++)
5202                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5203
5204                 // draw lighting in the unmasked areas
5205                 R_Shadow_RenderMode_Lighting(true, false, false, false);
5206                 if (numsurfaces)
5207                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5208                 for (i = 0;i < numlightentities;i++)
5209                         R_Shadow_DrawEntityLight(lightentities[i]);
5210
5211                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5212                 if (r_shadow_usingdeferredprepass)
5213                         R_Shadow_RenderMode_DrawDeferredLight(false);
5214         }
5215         else
5216         {
5217                 // draw lighting in the unmasked areas
5218                 R_Shadow_RenderMode_Lighting(false, false, false, false);
5219                 if (numsurfaces)
5220                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5221                 for (i = 0;i < numlightentities;i++)
5222                         R_Shadow_DrawEntityLight(lightentities[i]);
5223                 for (i = 0;i < numlightentities_noselfshadow;i++)
5224                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5225
5226                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5227                 if (r_shadow_usingdeferredprepass)
5228                         R_Shadow_RenderMode_DrawDeferredLight(false);
5229         }
5230 }
5231
5232 static void R_Shadow_FreeDeferred(void)
5233 {
5234         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5235         r_shadow_prepassgeometryfbo = 0;
5236
5237         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5238         r_shadow_prepasslightingdiffusespecularfbo = 0;
5239
5240         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5241         r_shadow_prepasslightingdiffusefbo = 0;
5242
5243         if (r_shadow_prepassgeometrydepthbuffer)
5244                 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5245         r_shadow_prepassgeometrydepthbuffer = NULL;
5246
5247         if (r_shadow_prepassgeometrynormalmaptexture)
5248                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5249         r_shadow_prepassgeometrynormalmaptexture = NULL;
5250
5251         if (r_shadow_prepasslightingdiffusetexture)
5252                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5253         r_shadow_prepasslightingdiffusetexture = NULL;
5254
5255         if (r_shadow_prepasslightingspeculartexture)
5256                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5257         r_shadow_prepasslightingspeculartexture = NULL;
5258 }
5259
5260 void R_Shadow_DrawPrepass(void)
5261 {
5262         int i;
5263         int lnum;
5264         entity_render_t *ent;
5265         float clearcolor[4];
5266
5267         R_Mesh_ResetTextureState();
5268         GL_DepthMask(true);
5269         GL_ColorMask(1,1,1,1);
5270         GL_BlendFunc(GL_ONE, GL_ZERO);
5271         GL_Color(1,1,1,1);
5272         GL_DepthTest(true);
5273         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5274         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5275         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5276         if (r_timereport_active)
5277                 R_TimeReport("prepasscleargeom");
5278
5279         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5280                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5281         if (r_timereport_active)
5282                 R_TimeReport("prepassworld");
5283
5284         for (i = 0;i < r_refdef.scene.numentities;i++)
5285         {
5286                 if (!r_refdef.viewcache.entityvisible[i])
5287                         continue;
5288                 ent = r_refdef.scene.entities[i];
5289                 if (ent->model && ent->model->DrawPrepass != NULL)
5290                         ent->model->DrawPrepass(ent);
5291         }
5292
5293         if (r_timereport_active)
5294                 R_TimeReport("prepassmodels");
5295
5296         GL_DepthMask(false);
5297         GL_ColorMask(1,1,1,1);
5298         GL_Color(1,1,1,1);
5299         GL_DepthTest(true);
5300         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5301         Vector4Set(clearcolor, 0, 0, 0, 0);
5302         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5303         if (r_timereport_active)
5304                 R_TimeReport("prepassclearlit");
5305
5306         R_Shadow_RenderMode_Begin();
5307
5308         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5309                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5310
5311         R_Shadow_RenderMode_End();
5312
5313         if (r_timereport_active)
5314                 R_TimeReport("prepasslights");
5315 }
5316
5317 #define MAX_SCENELIGHTS 65536
5318 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5319 {
5320         if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5321         {
5322                 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5323                         return false;
5324                 r_shadow_scenemaxlights *= 2;
5325                 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5326                 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5327         }
5328         r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5329         return true;
5330 }
5331
5332 void R_Shadow_DrawLightSprites(void);
5333 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5334 {
5335         int flag;
5336         int lnum;
5337         size_t lightindex;
5338         dlight_t *light;
5339         size_t range;
5340         float f;
5341
5342         int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5343         int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5344         int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5345
5346         if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5347                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5348                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5349                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5350                 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5351                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5352                 r_shadow_shadowmapborder != shadowmapborder ||
5353                 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5354                 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5355                 R_Shadow_FreeShadowMaps();
5356
5357         r_shadow_fb_fbo = fbo;
5358         r_shadow_fb_depthtexture = depthtexture;
5359         r_shadow_fb_colortexture = colortexture;
5360
5361         r_shadow_usingshadowmaportho = false;
5362
5363         switch (vid.renderpath)
5364         {
5365         case RENDERPATH_GL20:
5366         case RENDERPATH_D3D9:
5367         case RENDERPATH_D3D10:
5368         case RENDERPATH_D3D11:
5369         case RENDERPATH_SOFT:
5370 #ifndef USE_GLES2
5371                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5372                 {
5373                         r_shadow_usingdeferredprepass = false;
5374                         if (r_shadow_prepass_width)
5375                                 R_Shadow_FreeDeferred();
5376                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
5377                         break;
5378                 }
5379
5380                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5381                 {
5382                         R_Shadow_FreeDeferred();
5383
5384                         r_shadow_usingdeferredprepass = true;
5385                         r_shadow_prepass_width = vid.width;
5386                         r_shadow_prepass_height = vid.height;
5387                         r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5388                         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);
5389                         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);
5390                         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);
5391
5392                         // set up the geometry pass fbo (depth + normalmap)
5393                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5394                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5395                         // render depth into a renderbuffer and other important properties into the normalmap texture
5396
5397                         // set up the lighting pass fbo (diffuse + specular)
5398                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5399                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5400                         // render diffuse into one texture and specular into another,
5401                         // with depth and normalmap bound as textures,
5402                         // with depth bound as attachment as well
5403
5404                         // set up the lighting pass fbo (diffuse)
5405                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5406                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5407                         // render diffuse into one texture,
5408                         // with depth and normalmap bound as textures,
5409                         // with depth bound as attachment as well
5410                 }
5411 #endif
5412                 break;
5413         case RENDERPATH_GL11:
5414         case RENDERPATH_GL13:
5415         case RENDERPATH_GLES1:
5416         case RENDERPATH_GLES2:
5417                 r_shadow_usingdeferredprepass = false;
5418                 break;
5419         }
5420
5421         R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
5422
5423         r_shadow_scenenumlights = 0;
5424         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5425         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5426         for (lightindex = 0; lightindex < range; lightindex++)
5427         {
5428                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5429                 if (light && (light->flags & flag))
5430                 {
5431                         R_Shadow_PrepareLight(&light->rtlight);
5432                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5433                 }
5434         }
5435         if (r_refdef.scene.rtdlight)
5436         {
5437                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5438                 {
5439                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5440                         R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5441                 }
5442         }
5443         else if (gl_flashblend.integer)
5444         {
5445                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5446                 {
5447                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5448                         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5449                         VectorScale(rtlight->color, f, rtlight->currentcolor);
5450                 }
5451         }
5452
5453         // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5454         if (r_shadow_debuglight.integer >= 0)
5455         {
5456                 r_shadow_scenenumlights = 0;
5457                 lightindex = r_shadow_debuglight.integer;
5458                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5459                 if (light)
5460                 {
5461                         R_Shadow_PrepareLight(&light->rtlight);
5462                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5463                 }
5464         }
5465
5466         // if we're doing shadowmaps we need to prepare the atlas layout now
5467         if (R_Shadow_ShadowMappingEnabled())
5468         {
5469                 int lod;
5470
5471                 // allocate shadowmaps in the atlas now
5472                 // 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...
5473                 for (lod = 0; lod < 16; lod++)
5474                 {
5475                         int packing_success = 0;
5476                         int packing_failure = 0;
5477                         Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5478                         // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5479                         if (r_shadow_shadowmapatlas_modelshadows_size)
5480                                 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);
5481                         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5482                         {
5483                                 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5484                                 int size = rtlight->shadowmapsidesize >> lod;
5485                                 int width, height;
5486                                 if (!rtlight->castshadows)
5487                                         continue;
5488                                 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5489                                 width = size * 2;
5490                                 height = size * 3;
5491                                 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5492                                 if (rtlight->cached_numshadowentities_noselfshadow)
5493                                         width *= 2;
5494                                 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5495                                 {
5496                                         rtlight->shadowmapatlassidesize = size;
5497                                         packing_success++;
5498                                 }
5499                                 else
5500                                 {
5501                                         // note down that we failed to pack this one, it will have to disable shadows
5502                                         rtlight->shadowmapatlassidesize = 0;
5503                                         packing_failure++;
5504                                 }
5505                         }
5506                         // generally everything fits and we stop here on the first iteration
5507                         if (packing_failure == 0)
5508                                 break;
5509                 }
5510         }
5511
5512         if (r_editlights.integer)
5513                 R_Shadow_DrawLightSprites();
5514 }
5515
5516 void R_Shadow_DrawShadowMaps(void)
5517 {
5518         R_Shadow_RenderMode_Begin();
5519         R_Shadow_RenderMode_ActiveLight(NULL);
5520
5521         // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5522         R_Shadow_ClearShadowMapTexture();
5523
5524         // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5525         if (r_shadow_shadowmapatlas_modelshadows_size)
5526         {
5527                 R_Shadow_DrawModelShadowMaps();
5528                 // don't let sound skip if going slow
5529                 if (r_refdef.scene.extraupdate)
5530                         S_ExtraUpdate();
5531         }
5532
5533         if (R_Shadow_ShadowMappingEnabled())
5534         {
5535                 int lnum;
5536                 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5537                         R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5538         }
5539
5540         R_Shadow_RenderMode_End();
5541 }
5542
5543 void R_Shadow_DrawLights(void)
5544 {
5545         int lnum;
5546
5547         R_Shadow_RenderMode_Begin();
5548
5549         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5550                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5551
5552         R_Shadow_RenderMode_End();
5553 }
5554
5555 #define MAX_MODELSHADOWS 1024
5556 static int r_shadow_nummodelshadows;
5557 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5558
5559 void R_Shadow_PrepareModelShadows(void)
5560 {
5561         int i;
5562         float scale, size, radius, dot1, dot2;
5563         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5564         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5565         entity_render_t *ent;
5566
5567         r_shadow_nummodelshadows = 0;
5568         r_shadow_shadowmapatlas_modelshadows_size = 0;
5569
5570         if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5571                 return;
5572
5573         switch (r_shadow_shadowmode)
5574         {
5575         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5576                 if (r_shadows.integer >= 2)
5577                         break;
5578                 // fall through
5579         case R_SHADOW_SHADOWMODE_STENCIL:
5580                 if (!vid.stencil)
5581                         return;
5582                 for (i = 0; i < r_refdef.scene.numentities; i++)
5583                 {
5584                         ent = r_refdef.scene.entities[i];
5585                         if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5586                         {
5587                                 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5588                                         break;
5589                                 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5590                                 R_AnimCache_GetEntity(ent, false, false);
5591                         }
5592                 }
5593                 return;
5594         default:
5595                 return;
5596         }
5597
5598         size = 2 * r_shadow_shadowmapmaxsize;
5599         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5600         radius = 0.5f * size / scale;
5601
5602         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5603         VectorCopy(prvmshadowdir, shadowdir);
5604         VectorNormalize(shadowdir);
5605         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5606         dot2 = DotProduct(r_refdef.view.up, shadowdir);
5607         if (fabs(dot1) <= fabs(dot2))
5608                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5609         else
5610                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5611         VectorNormalize(shadowforward);
5612         CrossProduct(shadowdir, shadowforward, shadowright);
5613         Math_atov(r_shadows_focus.string, prvmshadowfocus);
5614         VectorCopy(prvmshadowfocus, shadowfocus);
5615         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5616         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5617         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5618         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5619         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5620                 dot1 = 1;
5621         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5622
5623         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5624         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5625         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5626         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5627         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5628         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5629
5630         for (i = 0; i < r_refdef.scene.numentities; i++)
5631         {
5632                 ent = r_refdef.scene.entities[i];
5633                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5634                         continue;
5635                 // cast shadows from anything of the map (submodels are optional)
5636                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5637                 {
5638                         if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5639                                 break;
5640                         r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5641                         R_AnimCache_GetEntity(ent, false, false);
5642                 }
5643         }
5644
5645         if (r_shadow_nummodelshadows)
5646         {
5647                 r_shadow_shadowmapatlas_modelshadows_x = 0;
5648                 r_shadow_shadowmapatlas_modelshadows_y = 0;
5649                 r_shadow_shadowmapatlas_modelshadows_size = size;
5650         }
5651 }
5652
5653 static void R_Shadow_DrawModelShadowMaps(void)
5654 {
5655         int i;
5656         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5657         entity_render_t *ent;
5658         vec3_t relativelightorigin;
5659         vec3_t relativelightdirection, relativeforward, relativeright;
5660         vec3_t relativeshadowmins, relativeshadowmaxs;
5661         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5662         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5663         float m[12];
5664         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5665         r_viewport_t viewport;
5666
5667         size = r_shadow_shadowmapatlas_modelshadows_size;
5668         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5669         radius = 0.5f / scale;
5670         nearclip = -r_shadows_throwdistance.value;
5671         farclip = r_shadows_throwdistance.value;
5672         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);
5673
5674         // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5675         r_shadow_modelshadowmap_parameters[0] = size;
5676         r_shadow_modelshadowmap_parameters[1] = size;
5677         r_shadow_modelshadowmap_parameters[2] = 1.0;
5678         r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5679         r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5680         r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5681         r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5682         r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5683         r_shadow_usingshadowmaportho = true;
5684
5685         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5686         VectorCopy(prvmshadowdir, shadowdir);
5687         VectorNormalize(shadowdir);
5688         Math_atov(r_shadows_focus.string, prvmshadowfocus);
5689         VectorCopy(prvmshadowfocus, shadowfocus);
5690         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5691         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5692         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5693         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5694         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5695         dot2 = DotProduct(r_refdef.view.up, shadowdir);
5696         if (fabs(dot1) <= fabs(dot2))
5697                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5698         else
5699                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5700         VectorNormalize(shadowforward);
5701         VectorM(scale, shadowforward, &m[0]);
5702         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5703                 dot1 = 1;
5704         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5705         CrossProduct(shadowdir, shadowforward, shadowright);
5706         VectorM(scale, shadowright, &m[4]);
5707         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5708         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5709         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5710         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5711         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5712         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);
5713         R_SetViewport(&viewport);
5714
5715         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5716
5717         // render into a slightly restricted region so that the borders of the
5718         // shadowmap area fade away, rather than streaking across everything
5719         // outside the usable area
5720         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5721
5722         for (i = 0;i < r_shadow_nummodelshadows;i++)
5723         {
5724                 ent = r_shadow_modelshadows[i];
5725                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5726                 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5727                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5728                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5729                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5730                 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5731                 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5732                 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5733                 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5734                 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5735                 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5736                 RSurf_ActiveModelEntity(ent, false, false, false);
5737                 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5738                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5739         }
5740
5741 #if 0
5742         if (r_test.integer)
5743         {
5744                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5745                 CHECKGLERROR
5746                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5747                 CHECKGLERROR
5748                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5749                 Cvar_SetValueQuick(&r_test, 0);
5750                 Z_Free(rawpixels);
5751         }
5752 #endif
5753
5754         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5755         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5756         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5757         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5758         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5759         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5760
5761         switch (vid.renderpath)
5762         {
5763         case RENDERPATH_GL11:
5764         case RENDERPATH_GL13:
5765         case RENDERPATH_GL20:
5766         case RENDERPATH_SOFT:
5767         case RENDERPATH_GLES1:
5768         case RENDERPATH_GLES2:
5769                 break;
5770         case RENDERPATH_D3D9:
5771         case RENDERPATH_D3D10:
5772         case RENDERPATH_D3D11:
5773 #ifdef MATRIX4x4_OPENGLORIENTATION
5774                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
5775                 r_shadow_shadowmapmatrix.m[0][1]        *= -1.0f;
5776                 r_shadow_shadowmapmatrix.m[0][2]        *= -1.0f;
5777                 r_shadow_shadowmapmatrix.m[0][3]        *= -1.0f;
5778 #else
5779                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
5780                 r_shadow_shadowmapmatrix.m[1][0]        *= -1.0f;
5781                 r_shadow_shadowmapmatrix.m[2][0]        *= -1.0f;
5782                 r_shadow_shadowmapmatrix.m[3][0]        *= -1.0f;
5783 #endif
5784                 break;
5785         }
5786 }
5787
5788 void R_Shadow_DrawModelShadows(void)
5789 {
5790         int i;
5791         float relativethrowdistance;
5792         entity_render_t *ent;
5793         vec3_t relativelightorigin;
5794         vec3_t relativelightdirection;
5795         vec3_t relativeshadowmins, relativeshadowmaxs;
5796         vec3_t tmp, shadowdir;
5797         prvm_vec3_t prvmshadowdir;
5798
5799         if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5800                 return;
5801
5802         R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5803         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5804         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5805         R_Shadow_RenderMode_Begin();
5806         R_Shadow_RenderMode_ActiveLight(NULL);
5807         r_shadow_lightscissor[0] = r_refdef.view.x;
5808         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5809         r_shadow_lightscissor[2] = r_refdef.view.width;
5810         r_shadow_lightscissor[3] = r_refdef.view.height;
5811         R_Shadow_RenderMode_StencilShadowVolumes(false);
5812
5813         // get shadow dir
5814         if (r_shadows.integer == 2)
5815         {
5816                 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5817                 VectorCopy(prvmshadowdir, shadowdir);
5818                 VectorNormalize(shadowdir);
5819         }
5820
5821         R_Shadow_ClearStencil();
5822
5823         for (i = 0;i < r_shadow_nummodelshadows;i++)
5824         {
5825                 ent = r_shadow_modelshadows[i];
5826
5827                 // cast shadows from anything of the map (submodels are optional)
5828                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5829                 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5830                 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5831                 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5832                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5833                 else
5834                 {
5835                         if(ent->entitynumber != 0)
5836                         {
5837                                 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5838                                 {
5839                                         // FIXME handle this
5840                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
5841                                 }
5842                                 else
5843                                 {
5844                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5845                                         int entnum, entnum2, recursion;
5846                                         entnum = entnum2 = ent->entitynumber;
5847                                         for(recursion = 32; recursion > 0; --recursion)
5848                                         {
5849                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
5850                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5851                                                         entnum = entnum2;
5852                                                 else
5853                                                         break;
5854                                         }
5855                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5856                                         {
5857                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5858                                                 // transform into modelspace of OUR entity
5859                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5860                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5861                                         }
5862                                         else
5863                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5864                                 }
5865                         }
5866                         else
5867                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5868                 }
5869
5870                 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5871                 RSurf_ActiveModelEntity(ent, false, false, false);
5872                 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5873                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5874         }
5875
5876         // not really the right mode, but this will disable any silly stencil features
5877         R_Shadow_RenderMode_End();
5878
5879         // set up ortho view for rendering this pass
5880         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5881         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5882         //GL_ScissorTest(true);
5883         //R_EntityMatrix(&identitymatrix);
5884         //R_Mesh_ResetTextureState();
5885         R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5886
5887         // set up a darkening blend on shadowed areas
5888         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5889         //GL_DepthRange(0, 1);
5890         //GL_DepthTest(false);
5891         //GL_DepthMask(false);
5892         //GL_PolygonOffset(0, 0);CHECKGLERROR
5893         GL_Color(0, 0, 0, r_shadows_darken.value);
5894         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5895         //GL_DepthFunc(GL_ALWAYS);
5896         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5897
5898         // apply the blend to the shadowed areas
5899         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5900         R_SetupShader_Generic_NoTexture(false, true);
5901         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5902
5903         // restore the viewport
5904         R_SetViewport(&r_refdef.view.viewport);
5905
5906         // restore other state to normal
5907         //R_Shadow_RenderMode_End();
5908 }
5909
5910 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5911 {
5912         float zdist;
5913         vec3_t centerorigin;
5914 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5915         float vertex3f[12];
5916 #endif
5917         // if it's too close, skip it
5918         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5919                 return;
5920         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5921         if (zdist < 32)
5922                 return;
5923         if (usequery && r_numqueries + 2 <= r_maxqueries)
5924         {
5925                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5926                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5927                 // 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
5928                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5929
5930                 switch(vid.renderpath)
5931                 {
5932                 case RENDERPATH_GL11:
5933                 case RENDERPATH_GL13:
5934                 case RENDERPATH_GL20:
5935                 case RENDERPATH_GLES1:
5936                 case RENDERPATH_GLES2:
5937 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5938                         CHECKGLERROR
5939                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5940                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5941                         GL_DepthFunc(GL_ALWAYS);
5942                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5943                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5944                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5945                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5946                         GL_DepthFunc(GL_LEQUAL);
5947                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5948                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5949                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5950                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5951                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5952                         CHECKGLERROR
5953 #endif
5954                         break;
5955                 case RENDERPATH_D3D9:
5956                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5957                         break;
5958                 case RENDERPATH_D3D10:
5959                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5960                         break;
5961                 case RENDERPATH_D3D11:
5962                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5963                         break;
5964                 case RENDERPATH_SOFT:
5965                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5966                         break;
5967                 }
5968         }
5969         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5970 }
5971
5972 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5973
5974 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5975 {
5976         vec3_t color;
5977         unsigned int occlude = 0;
5978         GLint allpixels = 0, visiblepixels = 0;
5979
5980         // now we have to check the query result
5981         if (rtlight->corona_queryindex_visiblepixels)
5982         {
5983                 switch(vid.renderpath)
5984                 {
5985                 case RENDERPATH_GL20:
5986                 case RENDERPATH_GLES1:
5987                 case RENDERPATH_GLES2:
5988 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5989                         // See if we can use the GPU-side method to prevent implicit sync
5990                         if (vid.support.arb_query_buffer_object) {
5991 #define BUFFER_OFFSET(i)    ((GLint *)((unsigned char*)NULL + (i)))
5992                                 if (!r_shadow_occlusion_buf) {
5993                                         qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5994                                         qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5995                                         qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5996                                 } else {
5997                                         qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5998                                 }
5999                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
6000                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
6001                                 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
6002                                 occlude = MATERIALFLAG_OCCLUDE;
6003                                 cscale *= rtlight->corona_visibility;
6004                                 CHECKGLERROR
6005                                 break;
6006                         }
6007                         // fallthrough
6008 #else
6009                         return;
6010 #endif
6011                 case RENDERPATH_GL11:
6012                 case RENDERPATH_GL13:
6013 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6014                         CHECKGLERROR
6015                         qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
6016                         qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
6017                         if (visiblepixels < 1 || allpixels < 1)
6018                                 return;
6019                         rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
6020                         cscale *= rtlight->corona_visibility;
6021                         CHECKGLERROR
6022                         break;
6023 #else
6024                         return;
6025 #endif
6026                 case RENDERPATH_D3D9:
6027                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6028                         return;
6029                 case RENDERPATH_D3D10:
6030                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6031                         return;
6032                 case RENDERPATH_D3D11:
6033                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6034                         return;
6035                 case RENDERPATH_SOFT:
6036                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6037                         return;
6038                 default:
6039                         return;
6040                 }
6041         }
6042         else
6043         {
6044                 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
6045                         return;
6046         }
6047         VectorScale(rtlight->currentcolor, cscale, color);
6048         if (VectorLength(color) > (1.0f / 256.0f))
6049         {
6050                 float vertex3f[12];
6051                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6052                 if(negated)
6053                 {
6054                         VectorNegate(color, color);
6055                         GL_BlendEquationSubtract(true);
6056                 }
6057                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6058                 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);
6059                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6060                 if(negated)
6061                         GL_BlendEquationSubtract(false);
6062         }
6063 }
6064
6065 void R_Shadow_DrawCoronas(void)
6066 {
6067         int i, flag;
6068         qboolean usequery = false;
6069         size_t lightindex;
6070         dlight_t *light;
6071         rtlight_t *rtlight;
6072         size_t range;
6073         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6074                 return;
6075         if (r_fb.water.renderingscene)
6076                 return;
6077         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6078         R_EntityMatrix(&identitymatrix);
6079
6080         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6081
6082         // check occlusion of coronas
6083         // use GL_ARB_occlusion_query if available
6084         // otherwise use raytraces
6085         r_numqueries = 0;
6086         switch (vid.renderpath)
6087         {
6088         case RENDERPATH_GL11:
6089         case RENDERPATH_GL13:
6090         case RENDERPATH_GL20:
6091         case RENDERPATH_GLES1:
6092         case RENDERPATH_GLES2:
6093                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6094 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6095                 if (usequery)
6096                 {
6097                         GL_ColorMask(0,0,0,0);
6098                         if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6099                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6100                         {
6101                                 i = r_maxqueries;
6102                                 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6103                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6104                                 CHECKGLERROR
6105                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6106                                 CHECKGLERROR
6107                         }
6108                         RSurf_ActiveWorldEntity();
6109                         GL_BlendFunc(GL_ONE, GL_ZERO);
6110                         GL_CullFace(GL_NONE);
6111                         GL_DepthMask(false);
6112                         GL_DepthRange(0, 1);
6113                         GL_PolygonOffset(0, 0);
6114                         GL_DepthTest(true);
6115                         R_Mesh_ResetTextureState();
6116                         R_SetupShader_Generic_NoTexture(false, false);
6117                 }
6118 #endif
6119                 break;
6120         case RENDERPATH_D3D9:
6121                 usequery = false;
6122                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6123                 break;
6124         case RENDERPATH_D3D10:
6125                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6126                 break;
6127         case RENDERPATH_D3D11:
6128                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6129                 break;
6130         case RENDERPATH_SOFT:
6131                 usequery = false;
6132                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6133                 break;
6134         }
6135         for (lightindex = 0;lightindex < range;lightindex++)
6136         {
6137                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6138                 if (!light)
6139                         continue;
6140                 rtlight = &light->rtlight;
6141                 rtlight->corona_visibility = 0;
6142                 rtlight->corona_queryindex_visiblepixels = 0;
6143                 rtlight->corona_queryindex_allpixels = 0;
6144                 if (!(rtlight->flags & flag))
6145                         continue;
6146                 if (rtlight->corona <= 0)
6147                         continue;
6148                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6149                         continue;
6150                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6151         }
6152         for (i = 0;i < r_refdef.scene.numlights;i++)
6153         {
6154                 rtlight = r_refdef.scene.lights[i];
6155                 rtlight->corona_visibility = 0;
6156                 rtlight->corona_queryindex_visiblepixels = 0;
6157                 rtlight->corona_queryindex_allpixels = 0;
6158                 if (!(rtlight->flags & flag))
6159                         continue;
6160                 if (rtlight->corona <= 0)
6161                         continue;
6162                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6163         }
6164         if (usequery)
6165                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6166
6167         // now draw the coronas using the query data for intensity info
6168         for (lightindex = 0;lightindex < range;lightindex++)
6169         {
6170                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6171                 if (!light)
6172                         continue;
6173                 rtlight = &light->rtlight;
6174                 if (rtlight->corona_visibility <= 0)
6175                         continue;
6176                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6177         }
6178         for (i = 0;i < r_refdef.scene.numlights;i++)
6179         {
6180                 rtlight = r_refdef.scene.lights[i];
6181                 if (rtlight->corona_visibility <= 0)
6182                         continue;
6183                 if (gl_flashblend.integer)
6184                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6185                 else
6186                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6187         }
6188 }
6189
6190
6191
6192 static dlight_t *R_Shadow_NewWorldLight(void)
6193 {
6194         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6195 }
6196
6197 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)
6198 {
6199         matrix4x4_t matrix;
6200
6201         // 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
6202
6203         // validate parameters
6204         if (!cubemapname)
6205                 cubemapname = "";
6206
6207         // copy to light properties
6208         VectorCopy(origin, light->origin);
6209         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6210         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6211         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6212         /*
6213         light->color[0] = max(color[0], 0);
6214         light->color[1] = max(color[1], 0);
6215         light->color[2] = max(color[2], 0);
6216         */
6217         light->color[0] = color[0];
6218         light->color[1] = color[1];
6219         light->color[2] = color[2];
6220         light->radius = max(radius, 0);
6221         light->style = style;
6222         light->shadow = shadowenable;
6223         light->corona = corona;
6224         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6225         light->coronasizescale = coronasizescale;
6226         light->ambientscale = ambientscale;
6227         light->diffusescale = diffusescale;
6228         light->specularscale = specularscale;
6229         light->flags = flags;
6230
6231         // update renderable light data
6232         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6233         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);
6234 }
6235
6236 static void R_Shadow_FreeWorldLight(dlight_t *light)
6237 {
6238         if (r_shadow_selectedlight == light)
6239                 r_shadow_selectedlight = NULL;
6240         R_RTLight_Uncompile(&light->rtlight);
6241         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6242 }
6243
6244 void R_Shadow_ClearWorldLights(void)
6245 {
6246         size_t lightindex;
6247         dlight_t *light;
6248         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6249         for (lightindex = 0;lightindex < range;lightindex++)
6250         {
6251                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6252                 if (light)
6253                         R_Shadow_FreeWorldLight(light);
6254         }
6255         r_shadow_selectedlight = NULL;
6256 }
6257
6258 static void R_Shadow_SelectLight(dlight_t *light)
6259 {
6260         if (r_shadow_selectedlight)
6261                 r_shadow_selectedlight->selected = false;
6262         r_shadow_selectedlight = light;
6263         if (r_shadow_selectedlight)
6264                 r_shadow_selectedlight->selected = true;
6265 }
6266
6267 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6268 {
6269         // this is never batched (there can be only one)
6270         float vertex3f[12];
6271         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6272         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6273         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6274 }
6275
6276 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6277 {
6278         float intensity;
6279         float s;
6280         vec3_t spritecolor;
6281         skinframe_t *skinframe;
6282         float vertex3f[12];
6283
6284         // this is never batched (due to the ent parameter changing every time)
6285         // so numsurfaces == 1 and surfacelist[0] == lightnumber
6286         const dlight_t *light = (dlight_t *)ent;
6287         s = EDLIGHTSPRSIZE;
6288
6289         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6290
6291         intensity = 0.5f;
6292         VectorScale(light->color, intensity, spritecolor);
6293         if (VectorLength(spritecolor) < 0.1732f)
6294                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6295         if (VectorLength(spritecolor) > 1.0f)
6296                 VectorNormalize(spritecolor);
6297
6298         // draw light sprite
6299         if (light->cubemapname[0] && !light->shadow)
6300                 skinframe = r_editlights_sprcubemapnoshadowlight;
6301         else if (light->cubemapname[0])
6302                 skinframe = r_editlights_sprcubemaplight;
6303         else if (!light->shadow)
6304                 skinframe = r_editlights_sprnoshadowlight;
6305         else
6306                 skinframe = r_editlights_sprlight;
6307
6308         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);
6309         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6310
6311         // draw selection sprite if light is selected
6312         if (light->selected)
6313         {
6314                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6315                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6316                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6317         }
6318 }
6319
6320 void R_Shadow_DrawLightSprites(void)
6321 {
6322         size_t lightindex;
6323         dlight_t *light;
6324         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6325         for (lightindex = 0;lightindex < range;lightindex++)
6326         {
6327                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6328                 if (light)
6329                         R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6330         }
6331         if (!r_editlights_lockcursor)
6332                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6333 }
6334
6335 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6336 {
6337         unsigned int range;
6338         dlight_t *light;
6339         rtlight_t *rtlight;
6340         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6341         if (lightindex >= range)
6342                 return -1;
6343         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6344         if (!light)
6345                 return 0;
6346         rtlight = &light->rtlight;
6347         //if (!(rtlight->flags & flag))
6348         //      return 0;
6349         VectorCopy(rtlight->shadoworigin, origin);
6350         *radius = rtlight->radius;
6351         VectorCopy(rtlight->color, color);
6352         return 1;
6353 }
6354
6355 static void R_Shadow_SelectLightInView(void)
6356 {
6357         float bestrating, rating, temp[3];
6358         dlight_t *best;
6359         size_t lightindex;
6360         dlight_t *light;
6361         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6362         best = NULL;
6363         bestrating = 0;
6364
6365         if (r_editlights_lockcursor)
6366                 return;
6367         for (lightindex = 0;lightindex < range;lightindex++)
6368         {
6369                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6370                 if (!light)
6371                         continue;
6372                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6373                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6374                 if (rating >= 0.95)
6375                 {
6376                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6377                         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)
6378                         {
6379                                 bestrating = rating;
6380                                 best = light;
6381                         }
6382                 }
6383         }
6384         R_Shadow_SelectLight(best);
6385 }
6386
6387 void R_Shadow_LoadWorldLights(void)
6388 {
6389         int n, a, style, shadow, flags;
6390         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6391         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6392         if (cl.worldmodel == NULL)
6393         {
6394                 Con_Print("No map loaded.\n");
6395                 return;
6396         }
6397         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6398         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6399         if (lightsstring)
6400         {
6401                 s = lightsstring;
6402                 n = 0;
6403                 while (*s)
6404                 {
6405                         /*
6406                         t = s;
6407                         shadow = true;
6408                         for (;COM_Parse(t, true) && strcmp(
6409                         if (COM_Parse(t, true))
6410                         {
6411                                 if (com_token[0] == '!')
6412                                 {
6413                                         shadow = false;
6414                                         origin[0] = atof(com_token+1);
6415                                 }
6416                                 else
6417                                         origin[0] = atof(com_token);
6418                                 if (Com_Parse(t
6419                         }
6420                         */
6421                         t = s;
6422                         while (*s && *s != '\n' && *s != '\r')
6423                                 s++;
6424                         if (!*s)
6425                                 break;
6426                         tempchar = *s;
6427                         shadow = true;
6428                         // check for modifier flags
6429                         if (*t == '!')
6430                         {
6431                                 shadow = false;
6432                                 t++;
6433                         }
6434                         *s = 0;
6435 #if _MSC_VER >= 1400
6436 #define sscanf sscanf_s
6437 #endif
6438                         cubemapname[sizeof(cubemapname)-1] = 0;
6439 #if MAX_QPATH != 128
6440 #error update this code if MAX_QPATH changes
6441 #endif
6442                         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
6443 #if _MSC_VER >= 1400
6444 , sizeof(cubemapname)
6445 #endif
6446 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6447                         *s = tempchar;
6448                         if (a < 18)
6449                                 flags = LIGHTFLAG_REALTIMEMODE;
6450                         if (a < 17)
6451                                 specularscale = 1;
6452                         if (a < 16)
6453                                 diffusescale = 1;
6454                         if (a < 15)
6455                                 ambientscale = 0;
6456                         if (a < 14)
6457                                 coronasizescale = 0.25f;
6458                         if (a < 13)
6459                                 VectorClear(angles);
6460                         if (a < 10)
6461                                 corona = 0;
6462                         if (a < 9 || !strcmp(cubemapname, "\"\""))
6463                                 cubemapname[0] = 0;
6464                         // remove quotes on cubemapname
6465                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6466                         {
6467                                 size_t namelen;
6468                                 namelen = strlen(cubemapname) - 2;
6469                                 memmove(cubemapname, cubemapname + 1, namelen);
6470                                 cubemapname[namelen] = '\0';
6471                         }
6472                         if (a < 8)
6473                         {
6474                                 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);
6475                                 break;
6476                         }
6477                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6478                         if (*s == '\r')
6479                                 s++;
6480                         if (*s == '\n')
6481                                 s++;
6482                         n++;
6483                 }
6484                 if (*s)
6485                         Con_Printf("invalid rtlights file \"%s\"\n", name);
6486                 Mem_Free(lightsstring);
6487         }
6488 }
6489
6490 void R_Shadow_SaveWorldLights(void)
6491 {
6492         size_t lightindex;
6493         dlight_t *light;
6494         size_t bufchars, bufmaxchars;
6495         char *buf, *oldbuf;
6496         char name[MAX_QPATH];
6497         char line[MAX_INPUTLINE];
6498         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6499         // I hate lines which are 3 times my screen size :( --blub
6500         if (!range)
6501                 return;
6502         if (cl.worldmodel == NULL)
6503         {
6504                 Con_Print("No map loaded.\n");
6505                 return;
6506         }
6507         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6508         bufchars = bufmaxchars = 0;
6509         buf = NULL;
6510         for (lightindex = 0;lightindex < range;lightindex++)
6511         {
6512                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6513                 if (!light)
6514                         continue;
6515                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6516                         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);
6517                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6518                         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]);
6519                 else
6520                         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);
6521                 if (bufchars + strlen(line) > bufmaxchars)
6522                 {
6523                         bufmaxchars = bufchars + strlen(line) + 2048;
6524                         oldbuf = buf;
6525                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6526                         if (oldbuf)
6527                         {
6528                                 if (bufchars)
6529                                         memcpy(buf, oldbuf, bufchars);
6530                                 Mem_Free(oldbuf);
6531                         }
6532                 }
6533                 if (strlen(line))
6534                 {
6535                         memcpy(buf + bufchars, line, strlen(line));
6536                         bufchars += strlen(line);
6537                 }
6538         }
6539         if (bufchars)
6540                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6541         if (buf)
6542                 Mem_Free(buf);
6543 }
6544
6545 void R_Shadow_LoadLightsFile(void)
6546 {
6547         int n, a, style;
6548         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6549         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6550         if (cl.worldmodel == NULL)
6551         {
6552                 Con_Print("No map loaded.\n");
6553                 return;
6554         }
6555         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6556         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6557         if (lightsstring)
6558         {
6559                 s = lightsstring;
6560                 n = 0;
6561                 while (*s)
6562                 {
6563                         t = s;
6564                         while (*s && *s != '\n' && *s != '\r')
6565                                 s++;
6566                         if (!*s)
6567                                 break;
6568                         tempchar = *s;
6569                         *s = 0;
6570                         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);
6571                         *s = tempchar;
6572                         if (a < 14)
6573                         {
6574                                 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);
6575                                 break;
6576                         }
6577                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6578                         radius = bound(15, radius, 4096);
6579                         VectorScale(color, (2.0f / (8388608.0f)), color);
6580                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6581                         if (*s == '\r')
6582                                 s++;
6583                         if (*s == '\n')
6584                                 s++;
6585                         n++;
6586                 }
6587                 if (*s)
6588                         Con_Printf("invalid lights file \"%s\"\n", name);
6589                 Mem_Free(lightsstring);
6590         }
6591 }
6592
6593 // tyrlite/hmap2 light types in the delay field
6594 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6595
6596 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6597 {
6598         int entnum;
6599         int style;
6600         int islight;
6601         int skin;
6602         int pflags;
6603         //int effects;
6604         int type;
6605         int n;
6606         char *entfiledata;
6607         const char *data;
6608         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6609         char key[256], value[MAX_INPUTLINE];
6610         char vabuf[1024];
6611
6612         if (cl.worldmodel == NULL)
6613         {
6614                 Con_Print("No map loaded.\n");
6615                 return;
6616         }
6617         // try to load a .ent file first
6618         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6619         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6620         // and if that is not found, fall back to the bsp file entity string
6621         if (!data)
6622                 data = cl.worldmodel->brush.entities;
6623         if (!data)
6624                 return;
6625         for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6626         {
6627                 type = LIGHTTYPE_MINUSX;
6628                 origin[0] = origin[1] = origin[2] = 0;
6629                 originhack[0] = originhack[1] = originhack[2] = 0;
6630                 angles[0] = angles[1] = angles[2] = 0;
6631                 color[0] = color[1] = color[2] = 1;
6632                 light[0] = light[1] = light[2] = 1;light[3] = 300;
6633                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6634                 fadescale = 1;
6635                 lightscale = 1;
6636                 style = 0;
6637                 skin = 0;
6638                 pflags = 0;
6639                 //effects = 0;
6640                 islight = false;
6641                 while (1)
6642                 {
6643                         if (!COM_ParseToken_Simple(&data, false, false, true))
6644                                 break; // error
6645                         if (com_token[0] == '}')
6646                                 break; // end of entity
6647                         if (com_token[0] == '_')
6648                                 strlcpy(key, com_token + 1, sizeof(key));
6649                         else
6650                                 strlcpy(key, com_token, sizeof(key));
6651                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
6652                                 key[strlen(key)-1] = 0;
6653                         if (!COM_ParseToken_Simple(&data, false, false, true))
6654                                 break; // error
6655                         strlcpy(value, com_token, sizeof(value));
6656
6657                         // now that we have the key pair worked out...
6658                         if (!strcmp("light", key))
6659                         {
6660                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6661                                 if (n == 1)
6662                                 {
6663                                         // quake
6664                                         light[0] = vec[0] * (1.0f / 256.0f);
6665                                         light[1] = vec[0] * (1.0f / 256.0f);
6666                                         light[2] = vec[0] * (1.0f / 256.0f);
6667                                         light[3] = vec[0];
6668                                 }
6669                                 else if (n == 4)
6670                                 {
6671                                         // halflife
6672                                         light[0] = vec[0] * (1.0f / 255.0f);
6673                                         light[1] = vec[1] * (1.0f / 255.0f);
6674                                         light[2] = vec[2] * (1.0f / 255.0f);
6675                                         light[3] = vec[3];
6676                                 }
6677                         }
6678                         else if (!strcmp("delay", key))
6679                                 type = atoi(value);
6680                         else if (!strcmp("origin", key))
6681                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6682                         else if (!strcmp("angle", key))
6683                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6684                         else if (!strcmp("angles", key))
6685                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6686                         else if (!strcmp("color", key))
6687                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6688                         else if (!strcmp("wait", key))
6689                                 fadescale = atof(value);
6690                         else if (!strcmp("classname", key))
6691                         {
6692                                 if (!strncmp(value, "light", 5))
6693                                 {
6694                                         islight = true;
6695                                         if (!strcmp(value, "light_fluoro"))
6696                                         {
6697                                                 originhack[0] = 0;
6698                                                 originhack[1] = 0;
6699                                                 originhack[2] = 0;
6700                                                 overridecolor[0] = 1;
6701                                                 overridecolor[1] = 1;
6702                                                 overridecolor[2] = 1;
6703                                         }
6704                                         if (!strcmp(value, "light_fluorospark"))
6705                                         {
6706                                                 originhack[0] = 0;
6707                                                 originhack[1] = 0;
6708                                                 originhack[2] = 0;
6709                                                 overridecolor[0] = 1;
6710                                                 overridecolor[1] = 1;
6711                                                 overridecolor[2] = 1;
6712                                         }
6713                                         if (!strcmp(value, "light_globe"))
6714                                         {
6715                                                 originhack[0] = 0;
6716                                                 originhack[1] = 0;
6717                                                 originhack[2] = 0;
6718                                                 overridecolor[0] = 1;
6719                                                 overridecolor[1] = 0.8;
6720                                                 overridecolor[2] = 0.4;
6721                                         }
6722                                         if (!strcmp(value, "light_flame_large_yellow"))
6723                                         {
6724                                                 originhack[0] = 0;
6725                                                 originhack[1] = 0;
6726                                                 originhack[2] = 0;
6727                                                 overridecolor[0] = 1;
6728                                                 overridecolor[1] = 0.5;
6729                                                 overridecolor[2] = 0.1;
6730                                         }
6731                                         if (!strcmp(value, "light_flame_small_yellow"))
6732                                         {
6733                                                 originhack[0] = 0;
6734                                                 originhack[1] = 0;
6735                                                 originhack[2] = 0;
6736                                                 overridecolor[0] = 1;
6737                                                 overridecolor[1] = 0.5;
6738                                                 overridecolor[2] = 0.1;
6739                                         }
6740                                         if (!strcmp(value, "light_torch_small_white"))
6741                                         {
6742                                                 originhack[0] = 0;
6743                                                 originhack[1] = 0;
6744                                                 originhack[2] = 0;
6745                                                 overridecolor[0] = 1;
6746                                                 overridecolor[1] = 0.5;
6747                                                 overridecolor[2] = 0.1;
6748                                         }
6749                                         if (!strcmp(value, "light_torch_small_walltorch"))
6750                                         {
6751                                                 originhack[0] = 0;
6752                                                 originhack[1] = 0;
6753                                                 originhack[2] = 0;
6754                                                 overridecolor[0] = 1;
6755                                                 overridecolor[1] = 0.5;
6756                                                 overridecolor[2] = 0.1;
6757                                         }
6758                                 }
6759                         }
6760                         else if (!strcmp("style", key))
6761                                 style = atoi(value);
6762                         else if (!strcmp("skin", key))
6763                                 skin = (int)atof(value);
6764                         else if (!strcmp("pflags", key))
6765                                 pflags = (int)atof(value);
6766                         //else if (!strcmp("effects", key))
6767                         //      effects = (int)atof(value);
6768                         else if (cl.worldmodel->type == mod_brushq3)
6769                         {
6770                                 if (!strcmp("scale", key))
6771                                         lightscale = atof(value);
6772                                 if (!strcmp("fade", key))
6773                                         fadescale = atof(value);
6774                         }
6775                 }
6776                 if (!islight)
6777                         continue;
6778                 if (lightscale <= 0)
6779                         lightscale = 1;
6780                 if (fadescale <= 0)
6781                         fadescale = 1;
6782                 if (color[0] == color[1] && color[0] == color[2])
6783                 {
6784                         color[0] *= overridecolor[0];
6785                         color[1] *= overridecolor[1];
6786                         color[2] *= overridecolor[2];
6787                 }
6788                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6789                 color[0] = color[0] * light[0];
6790                 color[1] = color[1] * light[1];
6791                 color[2] = color[2] * light[2];
6792                 switch (type)
6793                 {
6794                 case LIGHTTYPE_MINUSX:
6795                         break;
6796                 case LIGHTTYPE_RECIPX:
6797                         radius *= 2;
6798                         VectorScale(color, (1.0f / 16.0f), color);
6799                         break;
6800                 case LIGHTTYPE_RECIPXX:
6801                         radius *= 2;
6802                         VectorScale(color, (1.0f / 16.0f), color);
6803                         break;
6804                 default:
6805                 case LIGHTTYPE_NONE:
6806                         break;
6807                 case LIGHTTYPE_SUN:
6808                         break;
6809                 case LIGHTTYPE_MINUSXX:
6810                         break;
6811                 }
6812                 VectorAdd(origin, originhack, origin);
6813                 if (radius >= 1)
6814                         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);
6815         }
6816         if (entfiledata)
6817                 Mem_Free(entfiledata);
6818 }
6819
6820
6821 static void R_Shadow_SetCursorLocationForView(void)
6822 {
6823         vec_t dist, push;
6824         vec3_t dest, endpos;
6825         trace_t trace;
6826         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6827         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
6828         if (trace.fraction < 1)
6829         {
6830                 dist = trace.fraction * r_editlights_cursordistance.value;
6831                 push = r_editlights_cursorpushback.value;
6832                 if (push > dist)
6833                         push = dist;
6834                 push = -push;
6835                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6836                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6837         }
6838         else
6839         {
6840                 VectorClear( endpos );
6841         }
6842         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6843         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6844         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6845 }
6846
6847 void R_Shadow_UpdateWorldLightSelection(void)
6848 {
6849         if (r_editlights.integer)
6850         {
6851                 R_Shadow_SetCursorLocationForView();
6852                 R_Shadow_SelectLightInView();
6853         }
6854         else
6855                 R_Shadow_SelectLight(NULL);
6856 }
6857
6858 static void R_Shadow_EditLights_Clear_f(void)
6859 {
6860         R_Shadow_ClearWorldLights();
6861 }
6862
6863 void R_Shadow_EditLights_Reload_f(void)
6864 {
6865         if (!cl.worldmodel)
6866                 return;
6867         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6868         R_Shadow_ClearWorldLights();
6869         if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6870         {
6871                 R_Shadow_LoadWorldLights();
6872                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6873                         R_Shadow_LoadLightsFile();
6874         }
6875         if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6876         {
6877                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6878                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6879         }
6880 }
6881
6882 static void R_Shadow_EditLights_Save_f(void)
6883 {
6884         if (!cl.worldmodel)
6885                 return;
6886         R_Shadow_SaveWorldLights();
6887 }
6888
6889 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6890 {
6891         R_Shadow_ClearWorldLights();
6892         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6893 }
6894
6895 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6896 {
6897         R_Shadow_ClearWorldLights();
6898         R_Shadow_LoadLightsFile();
6899 }
6900
6901 static void R_Shadow_EditLights_Spawn_f(void)
6902 {
6903         vec3_t color;
6904         if (!r_editlights.integer)
6905         {
6906                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6907                 return;
6908         }
6909         if (Cmd_Argc() != 1)
6910         {
6911                 Con_Print("r_editlights_spawn does not take parameters\n");
6912                 return;
6913         }
6914         color[0] = color[1] = color[2] = 1;
6915         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6916 }
6917
6918 static void R_Shadow_EditLights_Edit_f(void)
6919 {
6920         vec3_t origin, angles, color;
6921         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6922         int style, shadows, flags, normalmode, realtimemode;
6923         char cubemapname[MAX_INPUTLINE];
6924         if (!r_editlights.integer)
6925         {
6926                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6927                 return;
6928         }
6929         if (!r_shadow_selectedlight)
6930         {
6931                 Con_Print("No selected light.\n");
6932                 return;
6933         }
6934         VectorCopy(r_shadow_selectedlight->origin, origin);
6935         VectorCopy(r_shadow_selectedlight->angles, angles);
6936         VectorCopy(r_shadow_selectedlight->color, color);
6937         radius = r_shadow_selectedlight->radius;
6938         style = r_shadow_selectedlight->style;
6939         if (r_shadow_selectedlight->cubemapname)
6940                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6941         else
6942                 cubemapname[0] = 0;
6943         shadows = r_shadow_selectedlight->shadow;
6944         corona = r_shadow_selectedlight->corona;
6945         coronasizescale = r_shadow_selectedlight->coronasizescale;
6946         ambientscale = r_shadow_selectedlight->ambientscale;
6947         diffusescale = r_shadow_selectedlight->diffusescale;
6948         specularscale = r_shadow_selectedlight->specularscale;
6949         flags = r_shadow_selectedlight->flags;
6950         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6951         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6952         if (!strcmp(Cmd_Argv(1), "origin"))
6953         {
6954                 if (Cmd_Argc() != 5)
6955                 {
6956                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6957                         return;
6958                 }
6959                 origin[0] = atof(Cmd_Argv(2));
6960                 origin[1] = atof(Cmd_Argv(3));
6961                 origin[2] = atof(Cmd_Argv(4));
6962         }
6963         else if (!strcmp(Cmd_Argv(1), "originscale"))
6964         {
6965                 if (Cmd_Argc() != 5)
6966                 {
6967                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6968                         return;
6969                 }
6970                 origin[0] *= atof(Cmd_Argv(2));
6971                 origin[1] *= atof(Cmd_Argv(3));
6972                 origin[2] *= atof(Cmd_Argv(4));
6973         }
6974         else if (!strcmp(Cmd_Argv(1), "originx"))
6975         {
6976                 if (Cmd_Argc() != 3)
6977                 {
6978                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6979                         return;
6980                 }
6981                 origin[0] = atof(Cmd_Argv(2));
6982         }
6983         else if (!strcmp(Cmd_Argv(1), "originy"))
6984         {
6985                 if (Cmd_Argc() != 3)
6986                 {
6987                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6988                         return;
6989                 }
6990                 origin[1] = atof(Cmd_Argv(2));
6991         }
6992         else if (!strcmp(Cmd_Argv(1), "originz"))
6993         {
6994                 if (Cmd_Argc() != 3)
6995                 {
6996                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6997                         return;
6998                 }
6999                 origin[2] = atof(Cmd_Argv(2));
7000         }
7001         else if (!strcmp(Cmd_Argv(1), "move"))
7002         {
7003                 if (Cmd_Argc() != 5)
7004                 {
7005                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7006                         return;
7007                 }
7008                 origin[0] += atof(Cmd_Argv(2));
7009                 origin[1] += atof(Cmd_Argv(3));
7010                 origin[2] += atof(Cmd_Argv(4));
7011         }
7012         else if (!strcmp(Cmd_Argv(1), "movex"))
7013         {
7014                 if (Cmd_Argc() != 3)
7015                 {
7016                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7017                         return;
7018                 }
7019                 origin[0] += atof(Cmd_Argv(2));
7020         }
7021         else if (!strcmp(Cmd_Argv(1), "movey"))
7022         {
7023                 if (Cmd_Argc() != 3)
7024                 {
7025                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7026                         return;
7027                 }
7028                 origin[1] += atof(Cmd_Argv(2));
7029         }
7030         else if (!strcmp(Cmd_Argv(1), "movez"))
7031         {
7032                 if (Cmd_Argc() != 3)
7033                 {
7034                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7035                         return;
7036                 }
7037                 origin[2] += atof(Cmd_Argv(2));
7038         }
7039         else if (!strcmp(Cmd_Argv(1), "angles"))
7040         {
7041                 if (Cmd_Argc() != 5)
7042                 {
7043                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7044                         return;
7045                 }
7046                 angles[0] = atof(Cmd_Argv(2));
7047                 angles[1] = atof(Cmd_Argv(3));
7048                 angles[2] = atof(Cmd_Argv(4));
7049         }
7050         else if (!strcmp(Cmd_Argv(1), "anglesx"))
7051         {
7052                 if (Cmd_Argc() != 3)
7053                 {
7054                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7055                         return;
7056                 }
7057                 angles[0] = atof(Cmd_Argv(2));
7058         }
7059         else if (!strcmp(Cmd_Argv(1), "anglesy"))
7060         {
7061                 if (Cmd_Argc() != 3)
7062                 {
7063                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7064                         return;
7065                 }
7066                 angles[1] = atof(Cmd_Argv(2));
7067         }
7068         else if (!strcmp(Cmd_Argv(1), "anglesz"))
7069         {
7070                 if (Cmd_Argc() != 3)
7071                 {
7072                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7073                         return;
7074                 }
7075                 angles[2] = atof(Cmd_Argv(2));
7076         }
7077         else if (!strcmp(Cmd_Argv(1), "color"))
7078         {
7079                 if (Cmd_Argc() != 5)
7080                 {
7081                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7082                         return;
7083                 }
7084                 color[0] = atof(Cmd_Argv(2));
7085                 color[1] = atof(Cmd_Argv(3));
7086                 color[2] = atof(Cmd_Argv(4));
7087         }
7088         else if (!strcmp(Cmd_Argv(1), "radius"))
7089         {
7090                 if (Cmd_Argc() != 3)
7091                 {
7092                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7093                         return;
7094                 }
7095                 radius = atof(Cmd_Argv(2));
7096         }
7097         else if (!strcmp(Cmd_Argv(1), "colorscale"))
7098         {
7099                 if (Cmd_Argc() == 3)
7100                 {
7101                         double scale = atof(Cmd_Argv(2));
7102                         color[0] *= scale;
7103                         color[1] *= scale;
7104                         color[2] *= scale;
7105                 }
7106                 else
7107                 {
7108                         if (Cmd_Argc() != 5)
7109                         {
7110                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
7111                                 return;
7112                         }
7113                         color[0] *= atof(Cmd_Argv(2));
7114                         color[1] *= atof(Cmd_Argv(3));
7115                         color[2] *= atof(Cmd_Argv(4));
7116                 }
7117         }
7118         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7119         {
7120                 if (Cmd_Argc() != 3)
7121                 {
7122                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7123                         return;
7124                 }
7125                 radius *= atof(Cmd_Argv(2));
7126         }
7127         else if (!strcmp(Cmd_Argv(1), "style"))
7128         {
7129                 if (Cmd_Argc() != 3)
7130                 {
7131                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7132                         return;
7133                 }
7134                 style = atoi(Cmd_Argv(2));
7135         }
7136         else if (!strcmp(Cmd_Argv(1), "cubemap"))
7137         {
7138                 if (Cmd_Argc() > 3)
7139                 {
7140                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7141                         return;
7142                 }
7143                 if (Cmd_Argc() == 3)
7144                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7145                 else
7146                         cubemapname[0] = 0;
7147         }
7148         else if (!strcmp(Cmd_Argv(1), "shadows"))
7149         {
7150                 if (Cmd_Argc() != 3)
7151                 {
7152                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7153                         return;
7154                 }
7155                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7156         }
7157         else if (!strcmp(Cmd_Argv(1), "corona"))
7158         {
7159                 if (Cmd_Argc() != 3)
7160                 {
7161                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7162                         return;
7163                 }
7164                 corona = atof(Cmd_Argv(2));
7165         }
7166         else if (!strcmp(Cmd_Argv(1), "coronasize"))
7167         {
7168                 if (Cmd_Argc() != 3)
7169                 {
7170                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7171                         return;
7172                 }
7173                 coronasizescale = atof(Cmd_Argv(2));
7174         }
7175         else if (!strcmp(Cmd_Argv(1), "ambient"))
7176         {
7177                 if (Cmd_Argc() != 3)
7178                 {
7179                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7180                         return;
7181                 }
7182                 ambientscale = atof(Cmd_Argv(2));
7183         }
7184         else if (!strcmp(Cmd_Argv(1), "diffuse"))
7185         {
7186                 if (Cmd_Argc() != 3)
7187                 {
7188                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7189                         return;
7190                 }
7191                 diffusescale = atof(Cmd_Argv(2));
7192         }
7193         else if (!strcmp(Cmd_Argv(1), "specular"))
7194         {
7195                 if (Cmd_Argc() != 3)
7196                 {
7197                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7198                         return;
7199                 }
7200                 specularscale = atof(Cmd_Argv(2));
7201         }
7202         else if (!strcmp(Cmd_Argv(1), "normalmode"))
7203         {
7204                 if (Cmd_Argc() != 3)
7205                 {
7206                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7207                         return;
7208                 }
7209                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7210         }
7211         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7212         {
7213                 if (Cmd_Argc() != 3)
7214                 {
7215                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7216                         return;
7217                 }
7218                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7219         }
7220         else
7221         {
7222                 Con_Print("usage: r_editlights_edit [property] [value]\n");
7223                 Con_Print("Selected light's properties:\n");
7224                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7225                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7226                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7227                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
7228                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
7229                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
7230                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7231                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
7232                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
7233                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
7234                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
7235                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
7236                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7237                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7238                 return;
7239         }
7240         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7241         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7242 }
7243
7244 static void R_Shadow_EditLights_EditAll_f(void)
7245 {
7246         size_t lightindex;
7247         dlight_t *light, *oldselected;
7248         size_t range;
7249
7250         if (!r_editlights.integer)
7251         {
7252                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7253                 return;
7254         }
7255
7256         oldselected = r_shadow_selectedlight;
7257         // EditLights doesn't seem to have a "remove" command or something so:
7258         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7259         for (lightindex = 0;lightindex < range;lightindex++)
7260         {
7261                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7262                 if (!light)
7263                         continue;
7264                 R_Shadow_SelectLight(light);
7265                 R_Shadow_EditLights_Edit_f();
7266         }
7267         // return to old selected (to not mess editing once selection is locked)
7268         R_Shadow_SelectLight(oldselected);
7269 }
7270
7271 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7272 {
7273         int lightnumber, lightcount;
7274         size_t lightindex, range;
7275         dlight_t *light;
7276         char temp[256];
7277         float x, y;
7278
7279         if (!r_editlights.integer)
7280                 return;
7281
7282         // update cvars so QC can query them
7283         if (r_shadow_selectedlight)
7284         {
7285                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7286                 Cvar_SetQuick(&r_editlights_current_origin, temp);
7287                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7288                 Cvar_SetQuick(&r_editlights_current_angles, temp);
7289                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7290                 Cvar_SetQuick(&r_editlights_current_color, temp);
7291                 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7292                 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7293                 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7294                 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7295                 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7296                 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7297                 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7298                 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7299                 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7300                 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7301                 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7302         }
7303
7304         // draw properties on screen
7305         if (!r_editlights_drawproperties.integer)
7306                 return;
7307         x = vid_conwidth.value - 320;
7308         y = 5;
7309         DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7310         lightnumber = -1;
7311         lightcount = 0;
7312         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7313         for (lightindex = 0;lightindex < range;lightindex++)
7314         {
7315                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7316                 if (!light)
7317                         continue;
7318                 if (light == r_shadow_selectedlight)
7319                         lightnumber = (int)lightindex;
7320                 lightcount++;
7321         }
7322         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;
7323         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;
7324         y += 8;
7325         if (r_shadow_selectedlight == NULL)
7326                 return;
7327         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;
7328         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;
7329         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;
7330         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;
7331         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;
7332         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;
7333         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;
7334         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;
7335         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;
7336         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;
7337         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;
7338         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;
7339         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;
7340         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;
7341         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;
7342         y += 8;
7343         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;
7344         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;
7345         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;
7346         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;
7347         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;
7348         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;
7349         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;
7350         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;
7351         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;
7352         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;
7353 }
7354
7355 static void R_Shadow_EditLights_ToggleShadow_f(void)
7356 {
7357         if (!r_editlights.integer)
7358         {
7359                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
7360                 return;
7361         }
7362         if (!r_shadow_selectedlight)
7363         {
7364                 Con_Print("No selected light.\n");
7365                 return;
7366         }
7367         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);
7368 }
7369
7370 static void R_Shadow_EditLights_ToggleCorona_f(void)
7371 {
7372         if (!r_editlights.integer)
7373         {
7374                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
7375                 return;
7376         }
7377         if (!r_shadow_selectedlight)
7378         {
7379                 Con_Print("No selected light.\n");
7380                 return;
7381         }
7382         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);
7383 }
7384
7385 static void R_Shadow_EditLights_Remove_f(void)
7386 {
7387         if (!r_editlights.integer)
7388         {
7389                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
7390                 return;
7391         }
7392         if (!r_shadow_selectedlight)
7393         {
7394                 Con_Print("No selected light.\n");
7395                 return;
7396         }
7397         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7398         r_shadow_selectedlight = NULL;
7399 }
7400
7401 static void R_Shadow_EditLights_Help_f(void)
7402 {
7403         Con_Print(
7404 "Documentation on r_editlights system:\n"
7405 "Settings:\n"
7406 "r_editlights : enable/disable editing mode\n"
7407 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7408 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7409 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7410 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7411 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7412 "Commands:\n"
7413 "r_editlights_help : this help\n"
7414 "r_editlights_clear : remove all lights\n"
7415 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7416 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7417 "r_editlights_save : save to .rtlights file\n"
7418 "r_editlights_spawn : create a light with default settings\n"
7419 "r_editlights_edit command : edit selected light - more documentation below\n"
7420 "r_editlights_remove : remove selected light\n"
7421 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7422 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7423 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7424 "Edit commands:\n"
7425 "origin x y z : set light location\n"
7426 "originx x: set x component of light location\n"
7427 "originy y: set y component of light location\n"
7428 "originz z: set z component of light location\n"
7429 "move x y z : adjust light location\n"
7430 "movex x: adjust x component of light location\n"
7431 "movey y: adjust y component of light location\n"
7432 "movez z: adjust z component of light location\n"
7433 "angles x y z : set light angles\n"
7434 "anglesx x: set x component of light angles\n"
7435 "anglesy y: set y component of light angles\n"
7436 "anglesz z: set z component of light angles\n"
7437 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7438 "radius radius : set radius (size) of light\n"
7439 "colorscale grey : multiply color of light (1 does nothing)\n"
7440 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7441 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7442 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7443 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7444 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7445 "cubemap basename : set filter cubemap of light\n"
7446 "shadows 1/0 : turn on/off shadows\n"
7447 "corona n : set corona intensity\n"
7448 "coronasize n : set corona size (0-1)\n"
7449 "ambient n : set ambient intensity (0-1)\n"
7450 "diffuse n : set diffuse intensity (0-1)\n"
7451 "specular n : set specular intensity (0-1)\n"
7452 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7453 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7454 "<nothing> : print light properties to console\n"
7455         );
7456 }
7457
7458 static void R_Shadow_EditLights_CopyInfo_f(void)
7459 {
7460         if (!r_editlights.integer)
7461         {
7462                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
7463                 return;
7464         }
7465         if (!r_shadow_selectedlight)
7466         {
7467                 Con_Print("No selected light.\n");
7468                 return;
7469         }
7470         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7471         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7472         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7473         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7474         if (r_shadow_selectedlight->cubemapname)
7475                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7476         else
7477                 r_shadow_bufferlight.cubemapname[0] = 0;
7478         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7479         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7480         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7481         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7482         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7483         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7484         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7485 }
7486
7487 static void R_Shadow_EditLights_PasteInfo_f(void)
7488 {
7489         if (!r_editlights.integer)
7490         {
7491                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
7492                 return;
7493         }
7494         if (!r_shadow_selectedlight)
7495         {
7496                 Con_Print("No selected light.\n");
7497                 return;
7498         }
7499         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);
7500 }
7501
7502 static void R_Shadow_EditLights_Lock_f(void)
7503 {
7504         if (!r_editlights.integer)
7505         {
7506                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
7507                 return;
7508         }
7509         if (r_editlights_lockcursor)
7510         {
7511                 r_editlights_lockcursor = false;
7512                 return;
7513         }
7514         if (!r_shadow_selectedlight)
7515         {
7516                 Con_Print("No selected light to lock on.\n");
7517                 return;
7518         }
7519         r_editlights_lockcursor = true;
7520 }
7521
7522 static void R_Shadow_EditLights_Init(void)
7523 {
7524         Cvar_RegisterVariable(&r_editlights);
7525         Cvar_RegisterVariable(&r_editlights_cursordistance);
7526         Cvar_RegisterVariable(&r_editlights_cursorpushback);
7527         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7528         Cvar_RegisterVariable(&r_editlights_cursorgrid);
7529         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7530         Cvar_RegisterVariable(&r_editlights_drawproperties);
7531         Cvar_RegisterVariable(&r_editlights_current_origin);
7532         Cvar_RegisterVariable(&r_editlights_current_angles);
7533         Cvar_RegisterVariable(&r_editlights_current_color);
7534         Cvar_RegisterVariable(&r_editlights_current_radius);
7535         Cvar_RegisterVariable(&r_editlights_current_corona);
7536         Cvar_RegisterVariable(&r_editlights_current_coronasize);
7537         Cvar_RegisterVariable(&r_editlights_current_style);
7538         Cvar_RegisterVariable(&r_editlights_current_shadows);
7539         Cvar_RegisterVariable(&r_editlights_current_cubemap);
7540         Cvar_RegisterVariable(&r_editlights_current_ambient);
7541         Cvar_RegisterVariable(&r_editlights_current_diffuse);
7542         Cvar_RegisterVariable(&r_editlights_current_specular);
7543         Cvar_RegisterVariable(&r_editlights_current_normalmode);
7544         Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7545         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7546         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7547         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)");
7548         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7549         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7550         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7551         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)");
7552         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7553         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7554         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7555         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7556         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7557         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7558         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)");
7559         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7560 }
7561
7562
7563
7564 /*
7565 =============================================================================
7566
7567 LIGHT SAMPLING
7568
7569 =============================================================================
7570 */
7571
7572 void R_LightPoint(float *color, const vec3_t p, const int flags)
7573 {
7574         int i, numlights, flag;
7575         float f, relativepoint[3], dist, dist2, lightradius2;
7576         vec3_t diffuse, n;
7577         rtlight_t *light;
7578         dlight_t *dlight;
7579
7580         if (r_fullbright.integer)
7581         {
7582                 VectorSet(color, 1, 1, 1);
7583                 return;
7584         }
7585
7586         VectorClear(color);
7587
7588         if (flags & LP_LIGHTMAP)
7589         {
7590                 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7591                 {
7592                         VectorClear(diffuse);
7593                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7594                         VectorAdd(color, diffuse, color);
7595                 }
7596                 else
7597                         VectorSet(color, 1, 1, 1);
7598                 color[0] += r_refdef.scene.ambient;
7599                 color[1] += r_refdef.scene.ambient;
7600                 color[2] += r_refdef.scene.ambient;
7601         }
7602
7603         if (flags & LP_RTWORLD)
7604         {
7605                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7606                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7607                 for (i = 0; i < numlights; i++)
7608                 {
7609                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7610                         if (!dlight)
7611                                 continue;
7612                         light = &dlight->rtlight;
7613                         if (!(light->flags & flag))
7614                                 continue;
7615                         // sample
7616                         lightradius2 = light->radius * light->radius;
7617                         VectorSubtract(light->shadoworigin, p, relativepoint);
7618                         dist2 = VectorLength2(relativepoint);
7619                         if (dist2 >= lightradius2)
7620                                 continue;
7621                         dist = sqrt(dist2) / light->radius;
7622                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7623                         if (f <= 0)
7624                                 continue;
7625                         // todo: add to both ambient and diffuse
7626                         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)
7627                                 VectorMA(color, f, light->currentcolor, color);
7628                 }
7629         }
7630         if (flags & LP_DYNLIGHT)
7631         {
7632                 // sample dlights
7633                 for (i = 0;i < r_refdef.scene.numlights;i++)
7634                 {
7635                         light = r_refdef.scene.lights[i];
7636                         // sample
7637                         lightradius2 = light->radius * light->radius;
7638                         VectorSubtract(light->shadoworigin, p, relativepoint);
7639                         dist2 = VectorLength2(relativepoint);
7640                         if (dist2 >= lightradius2)
7641                                 continue;
7642                         dist = sqrt(dist2) / light->radius;
7643                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7644                         if (f <= 0)
7645                                 continue;
7646                         // todo: add to both ambient and diffuse
7647                         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)
7648                                 VectorMA(color, f, light->color, color);
7649                 }
7650         }
7651 }
7652
7653 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7654 {
7655         int i, numlights, flag;
7656         rtlight_t *light;
7657         dlight_t *dlight;
7658         float relativepoint[3];
7659         float color[3];
7660         float dir[3];
7661         float dist;
7662         float dist2;
7663         float intensity;
7664         float sample[5*3];
7665         float lightradius2;
7666
7667         if (r_fullbright.integer)
7668         {
7669                 VectorSet(ambient, 1, 1, 1);
7670                 VectorClear(diffuse);
7671                 VectorClear(lightdir);
7672                 return;
7673         }
7674
7675         if (flags == LP_LIGHTMAP)
7676         {
7677                 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7678                 VectorClear(diffuse);
7679                 VectorClear(lightdir);
7680                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7681                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7682                 else
7683                         VectorSet(ambient, 1, 1, 1);
7684                 return;
7685         }
7686
7687         memset(sample, 0, sizeof(sample));
7688         VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7689
7690         if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7691         {
7692                 vec3_t tempambient;
7693                 VectorClear(tempambient);
7694                 VectorClear(color);
7695                 VectorClear(relativepoint);
7696                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7697                 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7698                 VectorScale(color, r_refdef.lightmapintensity, color);
7699                 VectorAdd(sample, tempambient, sample);
7700                 VectorMA(sample    , 0.5f            , color, sample    );
7701                 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7702                 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7703                 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7704                 // calculate a weighted average light direction as well
7705                 intensity = VectorLength(color);
7706                 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7707         }
7708
7709         if (flags & LP_RTWORLD)
7710         {
7711                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7712                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7713                 for (i = 0; i < numlights; i++)
7714                 {
7715                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7716                         if (!dlight)
7717                                 continue;
7718                         light = &dlight->rtlight;
7719                         if (!(light->flags & flag))
7720                                 continue;
7721                         // sample
7722                         lightradius2 = light->radius * light->radius;
7723                         VectorSubtract(light->shadoworigin, p, relativepoint);
7724                         dist2 = VectorLength2(relativepoint);
7725                         if (dist2 >= lightradius2)
7726                                 continue;
7727                         dist = sqrt(dist2) / light->radius;
7728                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7729                         if (intensity <= 0.0f)
7730                                 continue;
7731                         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)
7732                                 continue;
7733                         // scale down intensity to add to both ambient and diffuse
7734                         //intensity *= 0.5f;
7735                         VectorNormalize(relativepoint);
7736                         VectorScale(light->currentcolor, intensity, color);
7737                         VectorMA(sample    , 0.5f            , color, sample    );
7738                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7739                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7740                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7741                         // calculate a weighted average light direction as well
7742                         intensity *= VectorLength(color);
7743                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7744                 }
7745                 // FIXME: sample bouncegrid too!
7746         }
7747
7748         if (flags & LP_DYNLIGHT)
7749         {
7750                 // sample dlights
7751                 for (i = 0;i < r_refdef.scene.numlights;i++)
7752                 {
7753                         light = r_refdef.scene.lights[i];
7754                         // sample
7755                         lightradius2 = light->radius * light->radius;
7756                         VectorSubtract(light->shadoworigin, p, relativepoint);
7757                         dist2 = VectorLength2(relativepoint);
7758                         if (dist2 >= lightradius2)
7759                                 continue;
7760                         dist = sqrt(dist2) / light->radius;
7761                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7762                         if (intensity <= 0.0f)
7763                                 continue;
7764                         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)
7765                                 continue;
7766                         // scale down intensity to add to both ambient and diffuse
7767                         //intensity *= 0.5f;
7768                         VectorNormalize(relativepoint);
7769                         VectorScale(light->currentcolor, intensity, color);
7770                         VectorMA(sample    , 0.5f            , color, sample    );
7771                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7772                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7773                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7774                         // calculate a weighted average light direction as well
7775                         intensity *= VectorLength(color);
7776                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7777                 }
7778         }
7779
7780         // calculate the direction we'll use to reduce the sample to a directional light source
7781         VectorCopy(sample + 12, dir);
7782         //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7783         VectorNormalize(dir);
7784         // extract the diffuse color along the chosen direction and scale it
7785         diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7786         diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7787         diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7788         // subtract some of diffuse from ambient
7789         VectorMA(sample, -0.333f, diffuse, ambient);
7790         // store the normalized lightdir
7791         VectorCopy(dir, lightdir);
7792 }