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