]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
Rewrote bouncegrid path splatting, it now has a cone shape which grows with distance...
[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, requires gl_fbo 1"};
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", "4096", "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                 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2630                 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2631         }
2632         else
2633         {
2634                 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2635                 VectorSet(maxs,  1048576.0f,  1048576.0f,  1048576.0f);
2636         }
2637         VectorSubtract(maxs, mins, size);
2638         // now we can calculate the resolution we want
2639         c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2640         c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2641         c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2642         // figure out the exact texture size (honoring power of 2 if required)
2643         c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2644         c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2645         c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2646         if (vid.support.arb_texture_non_power_of_two)
2647         {
2648                 resolution[0] = c[0];
2649                 resolution[1] = c[1];
2650                 resolution[2] = c[2];
2651         }
2652         else
2653         {
2654                 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2655                 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2656                 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2657         }
2658         size[0] = spacing[0] * resolution[0];
2659         size[1] = spacing[1] * resolution[1];
2660         size[2] = spacing[2] * resolution[2];
2661
2662         // if dynamic we may or may not want to use the world bounds
2663         // if the dynamic size is smaller than the world bounds, use it instead
2664         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]))
2665         {
2666                 // we know the resolution we want
2667                 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2668                 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2669                 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2670                 // now we can calculate the texture size (power of 2 if required)
2671                 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2672                 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2673                 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2674                 if (vid.support.arb_texture_non_power_of_two)
2675                 {
2676                         resolution[0] = c[0];
2677                         resolution[1] = c[1];
2678                         resolution[2] = c[2];
2679                 }
2680                 else
2681                 {
2682                         for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2683                         for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2684                         for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2685                 }
2686                 size[0] = spacing[0] * resolution[0];
2687                 size[1] = spacing[1] * resolution[1];
2688                 size[2] = spacing[2] * resolution[2];
2689                 // center the rendering on the view
2690                 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2691                 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2692                 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2693         }
2694
2695         // recalculate the maxs in case the resolution was not satisfactory
2696         VectorAdd(mins, size, maxs);
2697
2698         // check if this changed the texture size
2699         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);
2700         r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2701         VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2702         VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2703         VectorCopy(size, r_shadow_bouncegrid_state.size);
2704         VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2705         VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2706         VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2707
2708         // reallocate pixels for this update if needed...
2709         r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2710         r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2711         r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2712         numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2713         if (r_shadow_bouncegrid_state.numpixels != numpixels)
2714         {
2715                 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2716                 r_shadow_bouncegrid_state.highpixels = NULL;
2717                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2718                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2719                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2720                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2721                 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2722                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2723                 r_shadow_bouncegrid_state.numpixels = numpixels;
2724         }
2725
2726         // update the bouncegrid matrix to put it in the world properly
2727         memset(m, 0, sizeof(m));
2728         m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2729         m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2730         m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2731         m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2732         m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2733         m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2734         m[15] = 1.0f;
2735         Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2736 }
2737
2738 // enumerate world rtlights and sum the overall amount of light in the world,
2739 // from that we can calculate a scaling factor to fairly distribute photons
2740 // to all the lights
2741 //
2742 // this modifies rtlight->photoncolor and rtlight->photons
2743 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2744 {
2745         float normalphotonscaling;
2746         float photonscaling;
2747         float photonintensity;
2748         float photoncount = 0.0f;
2749         float lightintensity;
2750         float radius;
2751         float s;
2752         float w;
2753         vec3_t cullmins;
2754         vec3_t cullmaxs;
2755         unsigned int lightindex;
2756         dlight_t *light;
2757         rtlight_t *rtlight;
2758         normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2759         for (lightindex = 0;lightindex < range2;lightindex++)
2760         {
2761                 if (lightindex < range)
2762                 {
2763                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2764                         if (!light)
2765                                 continue;
2766                         rtlight = &light->rtlight;
2767                         VectorClear(rtlight->bouncegrid_photoncolor);
2768                         rtlight->bouncegrid_photons = 0;
2769                         rtlight->bouncegrid_hits = 0;
2770                         rtlight->bouncegrid_traces = 0;
2771                         rtlight->bouncegrid_effectiveradius = 0;
2772                         if (!(light->flags & flag))
2773                                 continue;
2774                         if (settings->staticmode)
2775                         {
2776                                 // when static, we skip styled lights because they tend to change...
2777                                 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2778                                         continue;
2779                         }
2780                         else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2781                                 continue;
2782                 }
2783                 else
2784                 {
2785                         rtlight = r_refdef.scene.lights[lightindex - range];
2786                         VectorClear(rtlight->bouncegrid_photoncolor);
2787                         rtlight->bouncegrid_photons = 0;
2788                         rtlight->bouncegrid_hits = 0;
2789                         rtlight->bouncegrid_traces = 0;
2790                         rtlight->bouncegrid_effectiveradius = 0;
2791                 }
2792                 // draw only visible lights (major speedup)
2793                 radius = rtlight->radius * settings->lightradiusscale;
2794                 cullmins[0] = rtlight->shadoworigin[0] - radius;
2795                 cullmins[1] = rtlight->shadoworigin[1] - radius;
2796                 cullmins[2] = rtlight->shadoworigin[2] - radius;
2797                 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2798                 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2799                 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2800                 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2801                 if (!settings->staticmode)
2802                 {
2803                         if (R_CullBox(cullmins, cullmaxs))
2804                                 continue;
2805                         if (r_refdef.scene.worldmodel
2806                          && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2807                          && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2808                                 continue;
2809                         if (w * VectorLength2(rtlight->color) == 0.0f)
2810                                 continue;
2811                 }
2812                 // a light that does not emit any light before style is applied, can be
2813                 // skipped entirely (it may just be a corona)
2814                 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2815                         continue;
2816                 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2817                 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2818                 // skip lights that will emit no photons
2819                 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2820                         continue;
2821                 // shoot particles from this light
2822                 // use a calculation for the number of particles that will not
2823                 // vary with lightstyle, otherwise we get randomized particle
2824                 // distribution, the seeded random is only consistent for a
2825                 // consistent number of particles on this light...
2826                 s = rtlight->radius;
2827                 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2828                 if (lightindex >= range)
2829                         lightintensity *= settings->dlightparticlemultiplier;
2830                 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2831                 photoncount += rtlight->bouncegrid_photons;
2832                 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2833                 // if the lightstyle happens to be off right now, we can skip actually
2834                 // firing the photons, but we did have to count them in the total.
2835                 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2836                 //      rtlight->bouncegrid_photons = 0;
2837         }
2838         // the user provided an energyperphoton value which we try to use
2839         // if that results in too many photons to shoot this frame, then we cap it
2840         // which causes photons to appear/disappear from frame to frame, so we don't
2841         // like doing that in the typical case
2842         photonscaling = 1.0f;
2843         photonintensity = 1.0f;
2844         if (photoncount > settings->maxphotons)
2845         {
2846                 photonscaling = settings->maxphotons / photoncount;
2847                 photonintensity = 1.0f / photonscaling;
2848         }
2849
2850         // modify the lights to reflect our computed scaling
2851         for (lightindex = 0; lightindex < range2; lightindex++)
2852         {
2853                 if (lightindex < range)
2854                 {
2855                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2856                         if (!light)
2857                                 continue;
2858                         rtlight = &light->rtlight;
2859                 }
2860                 else
2861                         rtlight = r_refdef.scene.lights[lightindex - range];
2862                 rtlight->bouncegrid_photons *= photonscaling;
2863                 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2864         }
2865 }
2866
2867 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2868 {
2869         r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2870         r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2871         // we only really care about sorting by Z
2872         if (a->point[2] < b->point[2])
2873                 return -1;
2874         if (a->point[2] > b->point[2])
2875                 return 1;
2876         return 0;
2877 }
2878
2879 static void R_Shadow_BounceGrid_ClearPixels(void)
2880 {
2881         // clear the highpixels array we'll be accumulating into
2882         if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2883                 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2884         if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2885                 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2886         r_shadow_bouncegrid_state.highpixels_index = 0;
2887         r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2888         memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2889 }
2890
2891 static void R_Shadow_BounceGrid_PerformSplats(void)
2892 {
2893         r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2894         r_shadow_bouncegrid_splatpath_t *splatpath;
2895         float *highpixels = r_shadow_bouncegrid_state.highpixels;
2896         int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2897         int splatindex;
2898         vec3_t steppos;
2899         vec3_t stepdelta;
2900         vec3_t dir;
2901         vec_t lightpathsize_current;
2902         vec_t lightpathsize_perstep;
2903         float splatcolor[32];
2904         int resolution[3];
2905         int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2906         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2907         int numsteps;
2908         int step;
2909
2910         // hush warnings about uninitialized data - pixelbands doesn't change but...
2911         memset(splatcolor, 0, sizeof(splatcolor));
2912
2913         // we use this a lot, so get a local copy
2914         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2915
2916         // sort the splats before we execute them, to reduce cache misses
2917         if (r_shadow_bouncegrid_sortlightpaths.integer)
2918                 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2919
2920         splatpath = splatpaths;
2921         for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2922         {
2923                 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2924                 // accumulate average shotcolor
2925                 VectorCopy(splatpath->splatdir, dir);
2926                 splatcolor[ 0] = splatpath->splatcolor[0];
2927                 splatcolor[ 1] = splatpath->splatcolor[1];
2928                 splatcolor[ 2] = splatpath->splatcolor[2];
2929                 splatcolor[ 3] = 0.0f;
2930                 if (pixelbands > 1)
2931                 {
2932                         // store bentnormal in case the shader has a use for it,
2933                         // bentnormal is an intensity-weighted average of the directions,
2934                         // and will be normalized on conversion to texture pixels.
2935                         splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2936                         splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2937                         splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2938                         splatcolor[ 7] = splatpath->splatintensity;
2939                         // for each color component (R, G, B) calculate the amount that a
2940                         // direction contributes
2941                         splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2942                         splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2943                         splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2944                         splatcolor[11] = 0.0f;
2945                         splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2946                         splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2947                         splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2948                         splatcolor[15] = 0.0f;
2949                         splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2950                         splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2951                         splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2952                         splatcolor[19] = 0.0f;
2953                         // and do the same for negative directions
2954                         splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2955                         splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2956                         splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2957                         splatcolor[23] = 0.0f;
2958                         splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2959                         splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2960                         splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2961                         splatcolor[27] = 0.0f;
2962                         splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2963                         splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2964                         splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2965                         splatcolor[31] = 0.0f;
2966                 }
2967                 // calculate the number of steps we need to traverse this distance
2968                 VectorCopy(splatpath->point, steppos);
2969                 VectorCopy(splatpath->step, stepdelta);
2970                 numsteps = splatpath->remainingsplats;
2971                 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
2972                 lightpathsize_perstep = splatpath->splatsize_perstep;
2973                 for (step = 0;step < numsteps;step++)
2974                 {
2975                         // the middle row/column/layer of each splat are full intensity
2976                         float splatmins[3];
2977                         float splatmaxs[3];
2978                         if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
2979                                 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
2980                         splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
2981                         splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
2982                         splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
2983                         splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
2984                         splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
2985                         splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
2986                         if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
2987                         {
2988                                 // it is within bounds...  do the real work now
2989                                 int xi, yi, zi, band, row;
2990                                 float pixelpos[3];
2991                                 float w;
2992                                 float *p;
2993                                 float colorscale = 1.0f / lightpathsize_current;
2994                                 r_refdef.stats[r_stat_bouncegrid_splats]++;
2995                                 // accumulate light onto the pixels
2996                                 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
2997                                 {
2998                                         pixelpos[2] = zi + 0.5f;
2999                                         for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3000                                         {
3001                                                 pixelpos[1] = yi + 0.5f;
3002                                                 row = (zi*resolution[1] + yi)*resolution[0];
3003                                                 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3004                                                 {
3005                                                         pixelpos[0] = xi + 0.5f;
3006                                                         // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3007                                                         w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3008                                                         if (w > 0.0f)
3009                                                         {
3010                                                                 if (w > 1.0f)
3011                                                                         w = 1.0f;
3012                                                                 w *= colorscale;
3013                                                                 p = highpixels + 4 * (row + xi);
3014                                                                 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3015                                                                 {
3016                                                                         // add to the pixel color
3017                                                                         p[0] += splatcolor[band * 4 + 0] * w;
3018                                                                         p[1] += splatcolor[band * 4 + 1] * w;
3019                                                                         p[2] += splatcolor[band * 4 + 2] * w;
3020                                                                         p[3] += splatcolor[band * 4 + 3] * w;
3021                                                                 }
3022                                                         }
3023                                                 }
3024                                         }
3025                                 }
3026                         }
3027                         VectorAdd(steppos, stepdelta, steppos);
3028                         lightpathsize_current += lightpathsize_perstep;
3029                 }
3030         }
3031 }
3032
3033 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3034 {
3035         const float *inpixel;
3036         float *outpixel;
3037         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3038         int pixelband;
3039         unsigned int index;
3040         unsigned int x, y, z;
3041         unsigned int resolution[3];
3042         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3043         for (pixelband = 0;pixelband < pixelbands;pixelband++)
3044         {
3045                 for (z = 1;z < resolution[2]-1;z++)
3046                 {
3047                         for (y = 1;y < resolution[1]-1;y++)
3048                         {
3049                                 x = 1;
3050                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3051                                 inpixel = inpixels + 4*index;
3052                                 outpixel = outpixels + 4*index;
3053                                 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3054                                 {
3055                                         outpixel[0] = (inpixel[0] + inpixel[  off] + inpixel[0-off]) * (1.0f / 3.0);
3056                                         outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3057                                         outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3058                                         outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3059                                 }
3060                         }
3061                 }
3062         }
3063 }
3064
3065 static void R_Shadow_BounceGrid_BlurPixels(void)
3066 {
3067         float *pixels[4];
3068         unsigned int resolution[3];
3069
3070         if (!r_shadow_bouncegrid_state.settings.blur)
3071                 return;
3072         
3073         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3074
3075         pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3076         pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3077         pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3078         pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3079
3080         // blur on X
3081         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3082         // blur on Y
3083         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3084         // blur on Z
3085         R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3086
3087         // toggle the state, highpixels now points to pixels[3] result
3088         r_shadow_bouncegrid_state.highpixels_index ^= 1;
3089         r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3090 }
3091
3092 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3093 {
3094         int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3095         unsigned char *pixelsbgra8 = NULL;
3096         unsigned char *pixelbgra8;
3097         unsigned short *pixelsrgba16f = NULL;
3098         unsigned short *pixelrgba16f;
3099         float *pixelsrgba32f = NULL;
3100         float *highpixels = r_shadow_bouncegrid_state.highpixels;
3101         float *highpixel;
3102         float *bandpixel;
3103         unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3104         unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3105         unsigned int pixelband;
3106         unsigned int x, y, z;
3107         unsigned int index, bandindex;
3108         unsigned int resolution[3];
3109         int c[4];
3110         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3111
3112         if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3113         {
3114                 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3115                 r_shadow_bouncegrid_state.texture = NULL;
3116         }
3117
3118         // if bentnormals exist, we need to normalize and bias them for the shader
3119         if (pixelbands > 1)
3120         {
3121                 pixelband = 1;
3122                 for (z = 0;z < resolution[2]-1;z++)
3123                 {
3124                         for (y = 0;y < resolution[1]-1;y++)
3125                         {
3126                                 x = 1;
3127                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3128                                 highpixel = highpixels + 4*index;
3129                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3130                                 {
3131                                         // only convert pixels that were hit by photons
3132                                         if (highpixel[3] != 0.0f)
3133                                                 VectorNormalize(highpixel);
3134                                         VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3135                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
3136                                 }
3137                         }
3138                 }
3139         }
3140
3141         // start by clearing the pixels array - we won't be writing to all of it
3142         //
3143         // then process only the pixels that have at least some color, skipping
3144         // the higher bands for speed on pixels that are black
3145         switch (floatcolors)
3146         {
3147         case 0:
3148                 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3149                         r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3150                 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3151                 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3152                 {
3153                         if (pixelband == 1)
3154                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3155                         else
3156                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3157                 }
3158                 for (z = 1;z < resolution[2]-1;z++)
3159                 {
3160                         for (y = 1;y < resolution[1]-1;y++)
3161                         {
3162                                 x = 1;
3163                                 pixelband = 0;
3164                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3165                                 highpixel = highpixels + 4*index;
3166                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3167                                 {
3168                                         // only convert pixels that were hit by photons
3169                                         if (VectorLength2(highpixel))
3170                                         {
3171                                                 // normalize the bentnormal now
3172                                                 if (pixelbands > 1)
3173                                                 {
3174                                                         VectorNormalize(highpixel + pixelsperband * 4);
3175                                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
3176                                                 }
3177                                                 // process all of the pixelbands for this pixel
3178                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3179                                                 {
3180                                                         pixelbgra8 = pixelsbgra8 + 4*bandindex;
3181                                                         bandpixel = highpixels + 4*bandindex;
3182                                                         c[0] = (int)(bandpixel[0]*256.0f);
3183                                                         c[1] = (int)(bandpixel[1]*256.0f);
3184                                                         c[2] = (int)(bandpixel[2]*256.0f);
3185                                                         c[3] = (int)(bandpixel[3]*256.0f);
3186                                                         pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3187                                                         pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3188                                                         pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3189                                                         pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3190                                                 }
3191                                         }
3192                                 }
3193                         }
3194                 }
3195
3196                 if (!r_shadow_bouncegrid_state.createtexture)
3197                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3198                 else
3199                         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);
3200                 break;
3201         case 1:
3202                 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3203                         r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3204                 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3205                 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3206                 for (z = 1;z < resolution[2]-1;z++)
3207                 {
3208                         for (y = 1;y < resolution[1]-1;y++)
3209                         {
3210                                 x = 1;
3211                                 pixelband = 0;
3212                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3213                                 highpixel = highpixels + 4*index;
3214                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3215                                 {
3216                                         // only convert pixels that were hit by photons
3217                                         if (VectorLength2(highpixel))
3218                                         {
3219                                                 // process all of the pixelbands for this pixel
3220                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3221                                                 {
3222                                                         // time to have fun with IEEE 754 bit hacking...
3223                                                         union {
3224                                                                 float f[4];
3225                                                                 unsigned int raw[4];
3226                                                         } u;
3227                                                         pixelrgba16f = pixelsrgba16f + 4*bandindex;
3228                                                         bandpixel = highpixels + 4*bandindex;
3229                                                         VectorCopy4(bandpixel, u.f);
3230                                                         VectorCopy4(u.raw, c);
3231                                                         // this math supports negative numbers, snaps denormals to zero
3232                                                         //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3233                                                         //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3234                                                         //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3235                                                         //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3236                                                         // this math does not support negative
3237                                                         pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3238                                                         pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3239                                                         pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3240                                                         pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3241                                                 }
3242                                         }
3243                                 }
3244                         }
3245                 }
3246
3247                 if (!r_shadow_bouncegrid_state.createtexture)
3248                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3249                 else
3250                         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);
3251                 break;
3252         case 2:
3253                 // our native format happens to match, so this is easy.
3254                 pixelsrgba32f = highpixels;
3255
3256                 if (!r_shadow_bouncegrid_state.createtexture)
3257                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3258                 else
3259                         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);
3260                 break;
3261         }
3262
3263         r_shadow_bouncegrid_state.lastupdatetime = realtime;
3264 }
3265
3266 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3267 {
3268         vec3_t bouncerandom[10];
3269         dlight_t *light;
3270         int bouncecount;
3271         int hitsupercontentsmask;
3272         int skipsupercontentsmask;
3273         int maxbounce;
3274         int shootparticles;
3275         int shotparticles;
3276         float bounceminimumintensity2;
3277         trace_t cliptrace;
3278         //trace_t cliptrace2;
3279         //trace_t cliptrace3;
3280         unsigned int lightindex;
3281         unsigned int seed;
3282         randomseed_t randomseed;
3283         vec3_t shotcolor;
3284         vec3_t baseshotcolor;
3285         vec3_t surfcolor;
3286         vec3_t clipend;
3287         vec3_t clipstart;
3288         vec3_t clipdiff;
3289         vec_t radius;
3290         vec_t distancetraveled;
3291         vec_t s;
3292         rtlight_t *rtlight;
3293
3294         // compute a seed for the unstable random modes
3295         Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3296         seed = realtime * 1000.0;
3297
3298         r_shadow_bouncegrid_state.numsplatpaths = 0;
3299
3300         // figure out what we want to interact with
3301         if (settings.hitmodels)
3302                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3303         else
3304                 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3305         skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3306         maxbounce = settings.maxbounce;
3307
3308         for (lightindex = 0;lightindex < range2;lightindex++)
3309         {
3310                 if (lightindex < range)
3311                 {
3312                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3313                         if (!light)
3314                                 continue;
3315                         rtlight = &light->rtlight;
3316                 }
3317                 else
3318                         rtlight = r_refdef.scene.lights[lightindex - range];
3319                 // note that this code used to keep track of residual photons and
3320                 // distribute them evenly to achieve exactly a desired photon count,
3321                 // but that caused unwanted flickering in dynamic mode
3322                 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3323                 // skip if we won't be shooting any photons
3324                 if (!shootparticles)
3325                         continue;
3326                 radius = rtlight->radius * settings.lightradiusscale;
3327                 //s = settings.particleintensity / shootparticles;
3328                 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3329                 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3330                 if (VectorLength2(baseshotcolor) <= 0.0f)
3331                         continue;
3332                 r_refdef.stats[r_stat_bouncegrid_lights]++;
3333                 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3334                 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3335                 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3336
3337                 // for seeded random we start the RNG with the position of the light
3338                 if (settings.rng_seed >= 0)
3339                 {
3340                         union
3341                         {
3342                                 unsigned int i[4];
3343                                 float f[4];
3344                         }
3345                         u;
3346                         u.f[0] = rtlight->shadoworigin[0];
3347                         u.f[1] = rtlight->shadoworigin[1];
3348                         u.f[2] = rtlight->shadoworigin[2];
3349                         u.f[3] = 1;
3350                         switch (settings.rng_type)
3351                         {
3352                         default:
3353                         case 0:
3354                                 // we have to shift the seed provided by the user because the result must be odd
3355                                 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3356                                 break;
3357                         case 1:
3358                                 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3359                                 break;
3360                         }
3361                 }
3362
3363                 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3364                 {
3365                         VectorCopy(baseshotcolor, shotcolor);
3366                         VectorCopy(rtlight->shadoworigin, clipstart);
3367                         switch (settings.rng_type)
3368                         {
3369                         default:
3370                         case 0:
3371                                 VectorLehmerRandom(&randomseed, clipend);
3372                                 if (settings.bounceanglediffuse)
3373                                 {
3374                                         // we want random to be stable, so we still have to do all the random we would have done
3375                                         for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3376                                                 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3377                                 }
3378                                 break;
3379                         case 1:
3380                                 VectorCheeseRandom(seed, clipend);
3381                                 if (settings.bounceanglediffuse)
3382                                 {
3383                                         // we want random to be stable, so we still have to do all the random we would have done
3384                                         for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3385                                                 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3386                                 }
3387                                 break;
3388                         }
3389
3390                         // we want a uniform distribution spherically, not merely within the sphere
3391                         if (settings.normalizevectors)
3392                                 VectorNormalize(clipend);
3393
3394                         VectorMA(clipstart, radius, clipend, clipend);
3395                         distancetraveled = 0.0f;
3396                         for (bouncecount = 0;;bouncecount++)
3397                         {
3398                                 r_refdef.stats[r_stat_bouncegrid_traces]++;
3399                                 rtlight->bouncegrid_traces++;
3400                                 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3401                                 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3402                                 if (settings.staticmode || settings.rng_seed < 0)
3403                                 {
3404                                         // static mode fires a LOT of rays but none of them are identical, so they are not cached
3405                                         // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3406                                         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);
3407                                 }
3408                                 else
3409                                 {
3410                                         // dynamic mode fires many rays and most will match the cache from the previous frame
3411                                         cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3412                                 }
3413                                 if (bouncecount > 0 || settings.includedirectlighting)
3414                                 {
3415                                         vec3_t hitpos;
3416                                         VectorCopy(cliptrace.endpos, hitpos);
3417                                         R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3418                                 }
3419                                 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3420                                 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3421                                 if (rtlight->bouncegrid_effectiveradius < s)
3422                                         rtlight->bouncegrid_effectiveradius = s;
3423                                 if (cliptrace.fraction >= 1.0f)
3424                                         break;
3425                                 r_refdef.stats[r_stat_bouncegrid_hits]++;
3426                                 rtlight->bouncegrid_hits++;
3427                                 if (bouncecount >= maxbounce)
3428                                         break;
3429                                 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3430                                 // also clamp the resulting color to never add energy, even if the user requests extreme values
3431                                 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3432                                         VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3433                                 else
3434                                         VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3435                                 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3436                                 surfcolor[0] = min(surfcolor[0], 1.0f);
3437                                 surfcolor[1] = min(surfcolor[1], 1.0f);
3438                                 surfcolor[2] = min(surfcolor[2], 1.0f);
3439                                 VectorMultiply(shotcolor, surfcolor, shotcolor);
3440                                 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3441                                         break;
3442                                 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3443                                 if (settings.bounceanglediffuse)
3444                                 {
3445                                         // random direction, primarily along plane normal
3446                                         s = VectorDistance(cliptrace.endpos, clipend);
3447                                         VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3448                                         VectorNormalize(clipend);
3449                                         VectorScale(clipend, s, clipend);
3450                                 }
3451                                 else
3452                                 {
3453                                         // reflect the remaining portion of the line across plane normal
3454                                         VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3455                                         VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3456                                 }
3457                                 // calculate the new line start and end
3458                                 VectorCopy(cliptrace.endpos, clipstart);
3459                                 VectorAdd(clipstart, clipend, clipend);
3460                         }
3461                 }
3462         }
3463 }
3464
3465 void R_Shadow_UpdateBounceGridTexture(void)
3466 {
3467         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3468         r_shadow_bouncegrid_settings_t settings;
3469         qboolean enable = false;
3470         qboolean settingschanged;
3471         unsigned int range; // number of world lights
3472         unsigned int range1; // number of dynamic lights (or zero if disabled)
3473         unsigned int range2; // range+range1
3474
3475         enable = R_Shadow_BounceGrid_CheckEnable(flag);
3476         
3477         R_Shadow_BounceGrid_GenerateSettings(&settings);
3478         
3479         // changing intensity does not require an update
3480         r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3481
3482         settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3483
3484         // when settings change, we free everything as it is just simpler that way.
3485         if (settingschanged || !enable)
3486         {
3487                 // not enabled, make sure we free anything we don't need anymore.
3488                 if (r_shadow_bouncegrid_state.texture)
3489                 {
3490                         R_FreeTexture(r_shadow_bouncegrid_state.texture);
3491                         r_shadow_bouncegrid_state.texture = NULL;
3492                 }
3493                 r_shadow_bouncegrid_state.highpixels = NULL;
3494                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3495                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3496                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3497                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3498                 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3499                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3500                 r_shadow_bouncegrid_state.numpixels = 0;
3501                 r_shadow_bouncegrid_state.directional = false;
3502
3503                 if (!enable)
3504                         return;
3505         }
3506
3507         // if all the settings seem identical to the previous update, return
3508         if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3509                 return;
3510
3511         // store the new settings
3512         r_shadow_bouncegrid_state.settings = settings;
3513
3514         R_Shadow_BounceGrid_UpdateSpacing();
3515
3516         // get the range of light numbers we'll be looping over:
3517         // range = static lights
3518         // range1 = dynamic lights (optional)
3519         // range2 = range + range1
3520         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3521         range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3522         range2 = range + range1;
3523
3524         // calculate weighting factors for distributing photons among the lights
3525         R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3526
3527         // trace the photons from lights and accumulate illumination
3528         R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3529
3530         // clear the texture
3531         R_Shadow_BounceGrid_ClearPixels();
3532         
3533         // accumulate the light splatting into texture
3534         R_Shadow_BounceGrid_PerformSplats();
3535
3536         // apply a mild blur filter to the texture
3537         R_Shadow_BounceGrid_BlurPixels();
3538
3539         // convert the pixels to lower precision and upload the texture
3540         R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3541
3542         // after we compute the static lighting we don't need to keep the highpixels array around
3543         if (settings.staticmode)
3544         {
3545                 r_shadow_bouncegrid_state.highpixels = NULL;
3546                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3547                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3548                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3549                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3550                 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3551                 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3552         }
3553 }
3554
3555 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3556 {
3557         R_Shadow_RenderMode_Reset();
3558         GL_BlendFunc(GL_ONE, GL_ONE);
3559         GL_DepthRange(0, 1);
3560         GL_DepthTest(r_showshadowvolumes.integer < 2);
3561         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3562         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3563         GL_CullFace(GL_NONE);
3564         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3565 }
3566
3567 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3568 {
3569         R_Shadow_RenderMode_Reset();
3570         GL_BlendFunc(GL_ONE, GL_ONE);
3571         GL_DepthRange(0, 1);
3572         GL_DepthTest(r_showlighting.integer < 2);
3573         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3574         if (!transparent)
3575                 GL_DepthFunc(GL_EQUAL);
3576         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3577         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3578 }
3579
3580 void R_Shadow_RenderMode_End(void)
3581 {
3582         R_Shadow_RenderMode_Reset();
3583         R_Shadow_RenderMode_ActiveLight(NULL);
3584         GL_DepthMask(true);
3585         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3586         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3587 }
3588
3589 int bboxedges[12][2] =
3590 {
3591         // top
3592         {0, 1}, // +X
3593         {0, 2}, // +Y
3594         {1, 3}, // Y, +X
3595         {2, 3}, // X, +Y
3596         // bottom
3597         {4, 5}, // +X
3598         {4, 6}, // +Y
3599         {5, 7}, // Y, +X
3600         {6, 7}, // X, +Y
3601         // verticals
3602         {0, 4}, // +Z
3603         {1, 5}, // X, +Z
3604         {2, 6}, // Y, +Z
3605         {3, 7}, // XY, +Z
3606 };
3607
3608 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3609 {
3610         if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3611         {
3612                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3613                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3614                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3615                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3616                 return false;
3617         }
3618         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3619                 return true; // invisible
3620         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3621         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3622         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3623         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3624                 r_refdef.stats[r_stat_lights_scissored]++;
3625         return false;
3626 }
3627
3628 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3629 {
3630         int i;
3631         const float *vertex3f;
3632         const float *normal3f;
3633         float *color4f;
3634         float dist, dot, distintensity, shadeintensity, v[3], n[3];
3635         switch (r_shadow_rendermode)
3636         {
3637         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3638         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3639                 if (VectorLength2(diffusecolor) > 0)
3640                 {
3641                         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)
3642                         {
3643                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3644                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3645                                 if ((dot = DotProduct(n, v)) < 0)
3646                                 {
3647                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3648                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3649                                 }
3650                                 else
3651                                         VectorCopy(ambientcolor, color4f);
3652                                 if (r_refdef.fogenabled)
3653                                 {
3654                                         float f;
3655                                         f = RSurf_FogVertex(vertex3f);
3656                                         VectorScale(color4f, f, color4f);
3657                                 }
3658                                 color4f[3] = 1;
3659                         }
3660                 }
3661                 else
3662                 {
3663                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3664                         {
3665                                 VectorCopy(ambientcolor, color4f);
3666                                 if (r_refdef.fogenabled)
3667                                 {
3668                                         float f;
3669                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3670                                         f = RSurf_FogVertex(vertex3f);
3671                                         VectorScale(color4f + 4*i, f, color4f);
3672                                 }
3673                                 color4f[3] = 1;
3674                         }
3675                 }
3676                 break;
3677         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3678                 if (VectorLength2(diffusecolor) > 0)
3679                 {
3680                         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)
3681                         {
3682                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3683                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3684                                 {
3685                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3686                                         if ((dot = DotProduct(n, v)) < 0)
3687                                         {
3688                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3689                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3690                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3691                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3692                                         }
3693                                         else
3694                                         {
3695                                                 color4f[0] = ambientcolor[0] * distintensity;
3696                                                 color4f[1] = ambientcolor[1] * distintensity;
3697                                                 color4f[2] = ambientcolor[2] * distintensity;
3698                                         }
3699                                         if (r_refdef.fogenabled)
3700                                         {
3701                                                 float f;
3702                                                 f = RSurf_FogVertex(vertex3f);
3703                                                 VectorScale(color4f, f, color4f);
3704                                         }
3705                                 }
3706                                 else
3707                                         VectorClear(color4f);
3708                                 color4f[3] = 1;
3709                         }
3710                 }
3711                 else
3712                 {
3713                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3714                         {
3715                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3716                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3717                                 {
3718                                         color4f[0] = ambientcolor[0] * distintensity;
3719                                         color4f[1] = ambientcolor[1] * distintensity;
3720                                         color4f[2] = ambientcolor[2] * distintensity;
3721                                         if (r_refdef.fogenabled)
3722                                         {
3723                                                 float f;
3724                                                 f = RSurf_FogVertex(vertex3f);
3725                                                 VectorScale(color4f, f, color4f);
3726                                         }
3727                                 }
3728                                 else
3729                                         VectorClear(color4f);
3730                                 color4f[3] = 1;
3731                         }
3732                 }
3733                 break;
3734         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3735                 if (VectorLength2(diffusecolor) > 0)
3736                 {
3737                         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)
3738                         {
3739                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3740                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3741                                 {
3742                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3743                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3744                                         if ((dot = DotProduct(n, v)) < 0)
3745                                         {
3746                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3747                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3748                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3749                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3750                                         }
3751                                         else
3752                                         {
3753                                                 color4f[0] = ambientcolor[0] * distintensity;
3754                                                 color4f[1] = ambientcolor[1] * distintensity;
3755                                                 color4f[2] = ambientcolor[2] * distintensity;
3756                                         }
3757                                         if (r_refdef.fogenabled)
3758                                         {
3759                                                 float f;
3760                                                 f = RSurf_FogVertex(vertex3f);
3761                                                 VectorScale(color4f, f, color4f);
3762                                         }
3763                                 }
3764                                 else
3765                                         VectorClear(color4f);
3766                                 color4f[3] = 1;
3767                         }
3768                 }
3769                 else
3770                 {
3771                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3772                         {
3773                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3774                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3775                                 {
3776                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3777                                         color4f[0] = ambientcolor[0] * distintensity;
3778                                         color4f[1] = ambientcolor[1] * distintensity;
3779                                         color4f[2] = ambientcolor[2] * distintensity;
3780                                         if (r_refdef.fogenabled)
3781                                         {
3782                                                 float f;
3783                                                 f = RSurf_FogVertex(vertex3f);
3784                                                 VectorScale(color4f, f, color4f);
3785                                         }
3786                                 }
3787                                 else
3788                                         VectorClear(color4f);
3789                                 color4f[3] = 1;
3790                         }
3791                 }
3792                 break;
3793         default:
3794                 break;
3795         }
3796 }
3797
3798 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3799 {
3800         // used to display how many times a surface is lit for level design purposes
3801         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3802         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3803         RSurf_DrawBatch();
3804 }
3805
3806 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3807 {
3808         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3809         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3810         RSurf_DrawBatch();
3811 }
3812
3813 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3814 {
3815         int renders;
3816         int i;
3817         int stop;
3818         int newfirstvertex;
3819         int newlastvertex;
3820         int newnumtriangles;
3821         int *newe;
3822         const int *e;
3823         float *c;
3824         int maxtriangles = 1024;
3825         int newelements[1024*3];
3826         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3827         for (renders = 0;renders < 4;renders++)
3828         {
3829                 stop = true;
3830                 newfirstvertex = 0;
3831                 newlastvertex = 0;
3832                 newnumtriangles = 0;
3833                 newe = newelements;
3834                 // due to low fillrate on the cards this vertex lighting path is
3835                 // designed for, we manually cull all triangles that do not
3836                 // contain a lit vertex
3837                 // this builds batches of triangles from multiple surfaces and
3838                 // renders them at once
3839                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3840                 {
3841                         if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3842                         {
3843                                 if (newnumtriangles)
3844                                 {
3845                                         newfirstvertex = min(newfirstvertex, e[0]);
3846                                         newlastvertex  = max(newlastvertex, e[0]);
3847                                 }
3848                                 else
3849                                 {
3850                                         newfirstvertex = e[0];
3851                                         newlastvertex = e[0];
3852                                 }
3853                                 newfirstvertex = min(newfirstvertex, e[1]);
3854                                 newlastvertex  = max(newlastvertex, e[1]);
3855                                 newfirstvertex = min(newfirstvertex, e[2]);
3856                                 newlastvertex  = max(newlastvertex, e[2]);
3857                                 newe[0] = e[0];
3858                                 newe[1] = e[1];
3859                                 newe[2] = e[2];
3860                                 newnumtriangles++;
3861                                 newe += 3;
3862                                 if (newnumtriangles >= maxtriangles)
3863                                 {
3864                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3865                                         newnumtriangles = 0;
3866                                         newe = newelements;
3867                                         stop = false;
3868                                 }
3869                         }
3870                 }
3871                 if (newnumtriangles >= 1)
3872                 {
3873                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3874                         stop = false;
3875                 }
3876                 // if we couldn't find any lit triangles, exit early
3877                 if (stop)
3878                         break;
3879                 // now reduce the intensity for the next overbright pass
3880                 // we have to clamp to 0 here incase the drivers have improper
3881                 // handling of negative colors
3882                 // (some old drivers even have improper handling of >1 color)
3883                 stop = true;
3884                 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3885                 {
3886                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3887                         {
3888                                 c[0] = max(0, c[0] - 1);
3889                                 c[1] = max(0, c[1] - 1);
3890                                 c[2] = max(0, c[2] - 1);
3891                                 stop = false;
3892                         }
3893                         else
3894                                 VectorClear(c);
3895                 }
3896                 // another check...
3897                 if (stop)
3898                         break;
3899         }
3900 }
3901
3902 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3903 {
3904         // OpenGL 1.1 path (anything)
3905         float ambientcolorbase[3], diffusecolorbase[3];
3906         float ambientcolorpants[3], diffusecolorpants[3];
3907         float ambientcolorshirt[3], diffusecolorshirt[3];
3908         const float *surfacecolor = rsurface.texture->dlightcolor;
3909         const float *surfacepants = rsurface.colormap_pantscolor;
3910         const float *surfaceshirt = rsurface.colormap_shirtcolor;
3911         rtexture_t *basetexture = rsurface.texture->basetexture;
3912         rtexture_t *pantstexture = rsurface.texture->pantstexture;
3913         rtexture_t *shirttexture = rsurface.texture->shirttexture;
3914         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3915         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3916         ambientscale *= 2 * r_refdef.view.colorscale;
3917         diffusescale *= 2 * r_refdef.view.colorscale;
3918         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3919         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3920         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3921         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3922         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3923         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3924         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3925         rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3926         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3927         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3928         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3929         R_Mesh_TexBind(0, basetexture);
3930         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3931         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3932         switch(r_shadow_rendermode)
3933         {
3934         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3935                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3936                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3937                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3938                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3939                 break;
3940         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3941                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3942                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3943                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3944                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3945                 // fall through
3946         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3947                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3948                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3949                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3950                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3951                 break;
3952         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3953                 break;
3954         default:
3955                 break;
3956         }
3957         //R_Mesh_TexBind(0, basetexture);
3958         R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3959         if (dopants)
3960         {
3961                 R_Mesh_TexBind(0, pantstexture);
3962                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3963         }
3964         if (doshirt)
3965         {
3966                 R_Mesh_TexBind(0, shirttexture);
3967                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3968         }
3969 }
3970
3971 extern cvar_t gl_lightmaps;
3972 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3973 {
3974         float ambientscale, diffusescale, specularscale;
3975         qboolean negated;
3976         float lightcolor[3];
3977         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3978         ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3979         diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3980         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3981         if (!r_shadow_usenormalmap.integer)
3982         {
3983                 ambientscale += 1.0f * diffusescale;
3984                 diffusescale = 0;
3985                 specularscale = 0;
3986         }
3987         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3988                 return;
3989         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3990         if(negated)
3991         {
3992                 VectorNegate(lightcolor, lightcolor);
3993                 GL_BlendEquationSubtract(true);
3994         }
3995         RSurf_SetupDepthAndCulling();
3996         switch (r_shadow_rendermode)
3997         {
3998         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3999                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4000                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4001                 break;
4002         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4003                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
4004                 break;
4005         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4006         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4007         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4008         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4009                 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
4010                 break;
4011         default:
4012                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4013                 break;
4014         }
4015         if(negated)
4016                 GL_BlendEquationSubtract(false);
4017 }
4018
4019 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)
4020 {
4021         matrix4x4_t tempmatrix = *matrix;
4022         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4023
4024         // if this light has been compiled before, free the associated data
4025         R_RTLight_Uncompile(rtlight);
4026
4027         // clear it completely to avoid any lingering data
4028         memset(rtlight, 0, sizeof(*rtlight));
4029
4030         // copy the properties
4031         rtlight->matrix_lighttoworld = tempmatrix;
4032         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4033         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4034         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4035         VectorCopy(color, rtlight->color);
4036         rtlight->cubemapname[0] = 0;
4037         if (cubemapname && cubemapname[0])
4038                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4039         rtlight->shadow = shadow;
4040         rtlight->corona = corona;
4041         rtlight->style = style;
4042         rtlight->isstatic = isstatic;
4043         rtlight->coronasizescale = coronasizescale;
4044         rtlight->ambientscale = ambientscale;
4045         rtlight->diffusescale = diffusescale;
4046         rtlight->specularscale = specularscale;
4047         rtlight->flags = flags;
4048
4049         // compute derived data
4050         //rtlight->cullradius = rtlight->radius;
4051         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4052         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4053         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4054         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4055         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4056         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4057         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4058 }
4059
4060 // compiles rtlight geometry
4061 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4062 void R_RTLight_Compile(rtlight_t *rtlight)
4063 {
4064         int i;
4065         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4066         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4067         entity_render_t *ent = r_refdef.scene.worldentity;
4068         dp_model_t *model = r_refdef.scene.worldmodel;
4069         unsigned char *data;
4070         shadowmesh_t *mesh;
4071
4072         // compile the light
4073         rtlight->compiled = true;
4074         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4075         rtlight->static_numleafs = 0;
4076         rtlight->static_numleafpvsbytes = 0;
4077         rtlight->static_leaflist = NULL;
4078         rtlight->static_leafpvs = NULL;
4079         rtlight->static_numsurfaces = 0;
4080         rtlight->static_surfacelist = NULL;
4081         rtlight->static_shadowmap_receivers = 0x3F;
4082         rtlight->static_shadowmap_casters = 0x3F;
4083         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4084         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4085         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4086         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4087         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4088         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4089
4090         if (model && model->GetLightInfo)
4091         {
4092                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4093                 r_shadow_compilingrtlight = rtlight;
4094                 R_FrameData_SetMark();
4095                 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);
4096                 R_FrameData_ReturnToMark();
4097                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4098                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4099                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4100                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4101                 rtlight->static_numsurfaces = numsurfaces;
4102                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4103                 rtlight->static_numleafs = numleafs;
4104                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4105                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4106                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4107                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4108                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4109                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4110                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4111                 if (rtlight->static_numsurfaces)
4112                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4113                 if (rtlight->static_numleafs)
4114                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4115                 if (rtlight->static_numleafpvsbytes)
4116                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4117                 if (rtlight->static_numshadowtrispvsbytes)
4118                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4119                 if (rtlight->static_numlighttrispvsbytes)
4120                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4121                 R_FrameData_SetMark();
4122                 switch (rtlight->shadowmode)
4123                 {
4124                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4125                         if (model->CompileShadowMap && rtlight->shadow)
4126                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4127                         break;
4128                 default:
4129                         if (model->CompileShadowVolume && rtlight->shadow)
4130                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4131                         break;
4132                 }
4133                 R_FrameData_ReturnToMark();
4134                 // now we're done compiling the rtlight
4135                 r_shadow_compilingrtlight = NULL;
4136         }
4137
4138
4139         // use smallest available cullradius - box radius or light radius
4140         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4141         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4142
4143         shadowzpasstris = 0;
4144         if (rtlight->static_meshchain_shadow_zpass)
4145                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4146                         shadowzpasstris += mesh->numtriangles;
4147
4148         shadowzfailtris = 0;
4149         if (rtlight->static_meshchain_shadow_zfail)
4150                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4151                         shadowzfailtris += mesh->numtriangles;
4152
4153         lighttris = 0;
4154         if (rtlight->static_numlighttrispvsbytes)
4155                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4156                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4157                                 lighttris++;
4158
4159         shadowtris = 0;
4160         if (rtlight->static_numshadowtrispvsbytes)
4161                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4162                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4163                                 shadowtris++;
4164
4165         if (developer_extra.integer)
4166                 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);
4167 }
4168
4169 void R_RTLight_Uncompile(rtlight_t *rtlight)
4170 {
4171         if (rtlight->compiled)
4172         {
4173                 if (rtlight->static_meshchain_shadow_zpass)
4174                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4175                 rtlight->static_meshchain_shadow_zpass = NULL;
4176                 if (rtlight->static_meshchain_shadow_zfail)
4177                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4178                 rtlight->static_meshchain_shadow_zfail = NULL;
4179                 if (rtlight->static_meshchain_shadow_shadowmap)
4180                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4181                 rtlight->static_meshchain_shadow_shadowmap = NULL;
4182                 // these allocations are grouped
4183                 if (rtlight->static_surfacelist)
4184                         Mem_Free(rtlight->static_surfacelist);
4185                 rtlight->static_numleafs = 0;
4186                 rtlight->static_numleafpvsbytes = 0;
4187                 rtlight->static_leaflist = NULL;
4188                 rtlight->static_leafpvs = NULL;
4189                 rtlight->static_numsurfaces = 0;
4190                 rtlight->static_surfacelist = NULL;
4191                 rtlight->static_numshadowtrispvsbytes = 0;
4192                 rtlight->static_shadowtrispvs = NULL;
4193                 rtlight->static_numlighttrispvsbytes = 0;
4194                 rtlight->static_lighttrispvs = NULL;
4195                 rtlight->compiled = false;
4196         }
4197 }
4198
4199 void R_Shadow_UncompileWorldLights(void)
4200 {
4201         size_t lightindex;
4202         dlight_t *light;
4203         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4204         for (lightindex = 0;lightindex < range;lightindex++)
4205         {
4206                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4207                 if (!light)
4208                         continue;
4209                 R_RTLight_Uncompile(&light->rtlight);
4210         }
4211 }
4212
4213 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4214 {
4215         int i, j;
4216         mplane_t plane;
4217         // reset the count of frustum planes
4218         // see rtlight->cached_frustumplanes definition for how much this array
4219         // can hold
4220         rtlight->cached_numfrustumplanes = 0;
4221
4222         if (r_trippy.integer)
4223                 return;
4224
4225         // haven't implemented a culling path for ortho rendering
4226         if (!r_refdef.view.useperspective)
4227         {
4228                 // check if the light is on screen and copy the 4 planes if it is
4229                 for (i = 0;i < 4;i++)
4230                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4231                                 break;
4232                 if (i == 4)
4233                         for (i = 0;i < 4;i++)
4234                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4235                 return;
4236         }
4237
4238 #if 1
4239         // generate a deformed frustum that includes the light origin, this is
4240         // used to cull shadow casting surfaces that can not possibly cast a
4241         // shadow onto the visible light-receiving surfaces, which can be a
4242         // performance gain
4243         //
4244         // if the light origin is onscreen the result will be 4 planes exactly
4245         // if the light origin is offscreen on only one axis the result will
4246         // be exactly 5 planes (split-side case)
4247         // if the light origin is offscreen on two axes the result will be
4248         // exactly 4 planes (stretched corner case)
4249         for (i = 0;i < 4;i++)
4250         {
4251                 // quickly reject standard frustum planes that put the light
4252                 // origin outside the frustum
4253                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4254                         continue;
4255                 // copy the plane
4256                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4257         }
4258         // if all the standard frustum planes were accepted, the light is onscreen
4259         // otherwise we need to generate some more planes below...
4260         if (rtlight->cached_numfrustumplanes < 4)
4261         {
4262                 // at least one of the stock frustum planes failed, so we need to
4263                 // create one or two custom planes to enclose the light origin
4264                 for (i = 0;i < 4;i++)
4265                 {
4266                         // create a plane using the view origin and light origin, and a
4267                         // single point from the frustum corner set
4268                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4269                         VectorNormalize(plane.normal);
4270                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4271                         // see if this plane is backwards and flip it if so
4272                         for (j = 0;j < 4;j++)
4273                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4274                                         break;
4275                         if (j < 4)
4276                         {
4277                                 VectorNegate(plane.normal, plane.normal);
4278                                 plane.dist *= -1;
4279                                 // flipped plane, test again to see if it is now valid
4280                                 for (j = 0;j < 4;j++)
4281                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4282                                                 break;
4283                                 // if the plane is still not valid, then it is dividing the
4284                                 // frustum and has to be rejected
4285                                 if (j < 4)
4286                                         continue;
4287                         }
4288                         // we have created a valid plane, compute extra info
4289                         PlaneClassify(&plane);
4290                         // copy the plane
4291                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4292 #if 1
4293                         // if we've found 5 frustum planes then we have constructed a
4294                         // proper split-side case and do not need to keep searching for
4295                         // planes to enclose the light origin
4296                         if (rtlight->cached_numfrustumplanes == 5)
4297                                 break;
4298 #endif
4299                 }
4300         }
4301 #endif
4302
4303 #if 0
4304         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4305         {
4306                 plane = rtlight->cached_frustumplanes[i];
4307                 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));
4308         }
4309 #endif
4310
4311 #if 0
4312         // now add the light-space box planes if the light box is rotated, as any
4313         // caster outside the oriented light box is irrelevant (even if it passed
4314         // the worldspace light box, which is axial)
4315         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4316         {
4317                 for (i = 0;i < 6;i++)
4318                 {
4319                         vec3_t v;
4320                         VectorClear(v);
4321                         v[i >> 1] = (i & 1) ? -1 : 1;
4322                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4323                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4324                         plane.dist = VectorNormalizeLength(plane.normal);
4325                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4326                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4327                 }
4328         }
4329 #endif
4330
4331 #if 0
4332         // add the world-space reduced box planes
4333         for (i = 0;i < 6;i++)
4334         {
4335                 VectorClear(plane.normal);
4336                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4337                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4338                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4339         }
4340 #endif
4341
4342 #if 0
4343         {
4344         int j, oldnum;
4345         vec3_t points[8];
4346         vec_t bestdist;
4347         // reduce all plane distances to tightly fit the rtlight cull box, which
4348         // is in worldspace
4349         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4350         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4351         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4352         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4353         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4354         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4355         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4356         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4357         oldnum = rtlight->cached_numfrustumplanes;
4358         rtlight->cached_numfrustumplanes = 0;
4359         for (j = 0;j < oldnum;j++)
4360         {
4361                 // find the nearest point on the box to this plane
4362                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4363                 for (i = 1;i < 8;i++)
4364                 {
4365                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4366                         if (bestdist > dist)
4367                                 bestdist = dist;
4368                 }
4369                 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);
4370                 // if the nearest point is near or behind the plane, we want this
4371                 // plane, otherwise the plane is useless as it won't cull anything
4372                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4373                 {
4374                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
4375                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4376                 }
4377         }
4378         }
4379 #endif
4380 }
4381
4382 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4383 {
4384         shadowmesh_t *mesh;
4385
4386         RSurf_ActiveWorldEntity();
4387
4388         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4389         {
4390                 CHECKGLERROR
4391                 GL_CullFace(GL_NONE);
4392                 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4393                 for (;mesh;mesh = mesh->next)
4394                 {
4395                         if (!mesh->sidetotals[r_shadow_shadowmapside])
4396                                 continue;
4397                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4398                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4399                         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);
4400                 }
4401                 CHECKGLERROR
4402         }
4403         else if (r_refdef.scene.worldentity->model)
4404                 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);
4405
4406         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4407 }
4408
4409 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4410 {
4411         qboolean zpass = false;
4412         shadowmesh_t *mesh;
4413         int t, tend;
4414         int surfacelistindex;
4415         msurface_t *surface;
4416
4417         // if triangle neighbors are disabled, shadowvolumes are disabled
4418         if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4419                 return;
4420
4421         RSurf_ActiveWorldEntity();
4422
4423         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4424         {
4425                 CHECKGLERROR
4426                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4427                 {
4428                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4429                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4430                 }
4431                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4432                 for (;mesh;mesh = mesh->next)
4433                 {
4434                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4435                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4436                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4437                         {
4438                                 // increment stencil if frontface is infront of depthbuffer
4439                                 GL_CullFace(r_refdef.view.cullface_back);
4440                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4441                                 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);
4442                                 // decrement stencil if backface is infront of depthbuffer
4443                                 GL_CullFace(r_refdef.view.cullface_front);
4444                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4445                         }
4446                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4447                         {
4448                                 // decrement stencil if backface is behind depthbuffer
4449                                 GL_CullFace(r_refdef.view.cullface_front);
4450                                 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4451                                 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);
4452                                 // increment stencil if frontface is behind depthbuffer
4453                                 GL_CullFace(r_refdef.view.cullface_back);
4454                                 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4455                         }
4456                         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);
4457                 }
4458                 CHECKGLERROR
4459         }
4460         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4461         {
4462                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4463                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4464                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4465                 {
4466                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4467                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4468                                 if (CHECKPVSBIT(trispvs, t))
4469                                         shadowmarklist[numshadowmark++] = t;
4470                 }
4471                 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);
4472         }
4473         else if (numsurfaces)
4474         {
4475                 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);
4476         }
4477
4478         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4479 }
4480
4481 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4482 {
4483         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4484         vec_t relativeshadowradius;
4485         RSurf_ActiveModelEntity(ent, false, false, false);
4486         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4487         // we need to re-init the shader for each entity because the matrix changed
4488         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4489         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4490         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4491         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4492         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4493         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4494         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4495         switch (r_shadow_rendermode)
4496         {
4497         case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4498                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4499                 break;
4500         default:
4501                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4502                 break;
4503         }
4504         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4505 }
4506
4507 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4508 {
4509         // set up properties for rendering light onto this entity
4510         RSurf_ActiveModelEntity(ent, true, true, false);
4511         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4512         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4513         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4514         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4515 }
4516
4517 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4518 {
4519         if (!r_refdef.scene.worldmodel->DrawLight)
4520                 return;
4521
4522         // set up properties for rendering light onto this entity
4523         RSurf_ActiveWorldEntity();
4524         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4525         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4526         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4527         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4528
4529         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4530
4531         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4532 }
4533
4534 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4535 {
4536         dp_model_t *model = ent->model;
4537         if (!model->DrawLight)
4538                 return;
4539
4540         R_Shadow_SetupEntityLight(ent);
4541
4542         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4543
4544         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4545 }
4546
4547 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4548 {
4549         int i;
4550         float f;
4551         int numleafs, numsurfaces;
4552         int *leaflist, *surfacelist;
4553         unsigned char *leafpvs;
4554         unsigned char *shadowtrispvs;
4555         unsigned char *lighttrispvs;
4556         //unsigned char *surfacesides;
4557         int numlightentities;
4558         int numlightentities_noselfshadow;
4559         int numshadowentities;
4560         int numshadowentities_noselfshadow;
4561         // FIXME: bounds check lightentities and shadowentities, etc.
4562         static entity_render_t *lightentities[MAX_EDICTS];
4563         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4564         static entity_render_t *shadowentities[MAX_EDICTS];
4565         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4566         qboolean nolight;
4567         qboolean castshadows;
4568
4569         rtlight->draw = false;
4570         rtlight->cached_numlightentities = 0;
4571         rtlight->cached_numlightentities_noselfshadow = 0;
4572         rtlight->cached_numshadowentities = 0;
4573         rtlight->cached_numshadowentities_noselfshadow = 0;
4574         rtlight->cached_numsurfaces = 0;
4575         rtlight->cached_lightentities = NULL;
4576         rtlight->cached_lightentities_noselfshadow = NULL;
4577         rtlight->cached_shadowentities = NULL;
4578         rtlight->cached_shadowentities_noselfshadow = NULL;
4579         rtlight->cached_shadowtrispvs = NULL;
4580         rtlight->cached_lighttrispvs = NULL;
4581         rtlight->cached_surfacelist = NULL;
4582         rtlight->shadowmapsidesize = 0;
4583
4584         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4585         // skip lights that are basically invisible (color 0 0 0)
4586         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4587
4588         // loading is done before visibility checks because loading should happen
4589         // all at once at the start of a level, not when it stalls gameplay.
4590         // (especially important to benchmarks)
4591         // compile light
4592         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4593         {
4594                 if (rtlight->compiled)
4595                         R_RTLight_Uncompile(rtlight);
4596                 R_RTLight_Compile(rtlight);
4597         }
4598
4599         // load cubemap
4600         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4601
4602         // look up the light style value at this time
4603         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4604         VectorScale(rtlight->color, f, rtlight->currentcolor);
4605         /*
4606         if (rtlight->selected)
4607         {
4608                 f = 2 + sin(realtime * M_PI * 4.0);
4609                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4610         }
4611         */
4612
4613         // if lightstyle is currently off, don't draw the light
4614         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4615                 return;
4616
4617         // skip processing on corona-only lights
4618         if (nolight)
4619                 return;
4620
4621         // if the light box is offscreen, skip it
4622         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4623                 return;
4624
4625         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4626         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4627
4628         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4629
4630         // 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
4631         if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4632                 return;
4633
4634         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4635         {
4636                 // compiled light, world available and can receive realtime lighting
4637                 // retrieve leaf information
4638                 numleafs = rtlight->static_numleafs;
4639                 leaflist = rtlight->static_leaflist;
4640                 leafpvs = rtlight->static_leafpvs;
4641                 numsurfaces = rtlight->static_numsurfaces;
4642                 surfacelist = rtlight->static_surfacelist;
4643                 //surfacesides = NULL;
4644                 shadowtrispvs = rtlight->static_shadowtrispvs;
4645                 lighttrispvs = rtlight->static_lighttrispvs;
4646         }
4647         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4648         {
4649                 // dynamic light, world available and can receive realtime lighting
4650                 // calculate lit surfaces and leafs
4651                 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);
4652                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4653                 leaflist = r_shadow_buffer_leaflist;
4654                 leafpvs = r_shadow_buffer_leafpvs;
4655                 surfacelist = r_shadow_buffer_surfacelist;
4656                 //surfacesides = r_shadow_buffer_surfacesides;
4657                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4658                 lighttrispvs = r_shadow_buffer_lighttrispvs;
4659                 // if the reduced leaf bounds are offscreen, skip it
4660                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4661                         return;
4662         }
4663         else
4664         {
4665                 // no world
4666                 numleafs = 0;
4667                 leaflist = NULL;
4668                 leafpvs = NULL;
4669                 numsurfaces = 0;
4670                 surfacelist = NULL;
4671                 //surfacesides = NULL;
4672                 shadowtrispvs = NULL;
4673                 lighttrispvs = NULL;
4674         }
4675         // check if light is illuminating any visible leafs
4676         if (numleafs)
4677         {
4678                 for (i = 0; i < numleafs; i++)
4679                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4680                                 break;
4681                 if (i == numleafs)
4682                         return;
4683         }
4684
4685         // make a list of lit entities and shadow casting entities
4686         numlightentities = 0;
4687         numlightentities_noselfshadow = 0;
4688         numshadowentities = 0;
4689         numshadowentities_noselfshadow = 0;
4690
4691         // add dynamic entities that are lit by the light
4692         for (i = 0; i < r_refdef.scene.numentities; i++)
4693         {
4694                 dp_model_t *model;
4695                 entity_render_t *ent = r_refdef.scene.entities[i];
4696                 vec3_t org;
4697                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4698                         continue;
4699                 // skip the object entirely if it is not within the valid
4700                 // shadow-casting region (which includes the lit region)
4701                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4702                         continue;
4703                 if (!(model = ent->model))
4704                         continue;
4705                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4706                 {
4707                         // this entity wants to receive light, is visible, and is
4708                         // inside the light box
4709                         // TODO: check if the surfaces in the model can receive light
4710                         // so now check if it's in a leaf seen by the light
4711                         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))
4712                                 continue;
4713                         if (ent->flags & RENDER_NOSELFSHADOW)
4714                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4715                         else
4716                                 lightentities[numlightentities++] = ent;
4717                         // since it is lit, it probably also casts a shadow...
4718                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4719                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4720                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4721                         {
4722                                 // note: exterior models without the RENDER_NOSELFSHADOW
4723                                 // flag still create a RENDER_NOSELFSHADOW shadow but
4724                                 // are lit normally, this means that they are
4725                                 // self-shadowing but do not shadow other
4726                                 // RENDER_NOSELFSHADOW entities such as the gun
4727                                 // (very weird, but keeps the player shadow off the gun)
4728                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4729                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4730                                 else
4731                                         shadowentities[numshadowentities++] = ent;
4732                         }
4733                 }
4734                 else if (ent->flags & RENDER_SHADOW)
4735                 {
4736                         // this entity is not receiving light, but may still need to
4737                         // cast a shadow...
4738                         // TODO: check if the surfaces in the model can cast shadow
4739                         // now check if it is in a leaf seen by the light
4740                         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))
4741                                 continue;
4742                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4743                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4744                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4745                         {
4746                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4747                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4748                                 else
4749                                         shadowentities[numshadowentities++] = ent;
4750                         }
4751                 }
4752         }
4753
4754         // return if there's nothing at all to light
4755         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4756                 return;
4757
4758         // count this light in the r_speeds
4759         r_refdef.stats[r_stat_lights]++;
4760
4761         // flag it as worth drawing later
4762         rtlight->draw = true;
4763
4764         // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4765         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4766         if (!castshadows)
4767                 numshadowentities = numshadowentities_noselfshadow = 0;
4768         rtlight->castshadows = castshadows;
4769
4770         // cache all the animated entities that cast a shadow but are not visible
4771         for (i = 0; i < numshadowentities; i++)
4772                 R_AnimCache_GetEntity(shadowentities[i], false, false);
4773         for (i = 0; i < numshadowentities_noselfshadow; i++)
4774                 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4775
4776         // 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)
4777         if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4778         {
4779                 for (i = 0; i < numshadowentities_noselfshadow; i++)
4780                         shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4781                 numshadowentities_noselfshadow = 0;
4782         }
4783
4784         // we can convert noselfshadow to regular if there are no casters of that type
4785         if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4786         {
4787                 for (i = 0; i < numlightentities_noselfshadow; i++)
4788                         lightentities[numlightentities++] = lightentities_noselfshadow[i];
4789                 numlightentities_noselfshadow = 0;
4790         }
4791
4792         // allocate some temporary memory for rendering this light later in the frame
4793         // reusable buffers need to be copied, static data can be used as-is
4794         rtlight->cached_numlightentities               = numlightentities;
4795         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
4796         rtlight->cached_numshadowentities              = numshadowentities;
4797         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4798         rtlight->cached_numsurfaces                    = numsurfaces;
4799         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4800         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4801         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4802         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4803         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4804         {
4805                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4806                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4807                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4808                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4809                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4810         }
4811         else
4812         {
4813                 // compiled light data
4814                 rtlight->cached_shadowtrispvs = shadowtrispvs;
4815                 rtlight->cached_lighttrispvs = lighttrispvs;
4816                 rtlight->cached_surfacelist = surfacelist;
4817         }
4818
4819         if (R_Shadow_ShadowMappingEnabled())
4820         {
4821                 // figure out the shadowmapping parameters for this light
4822                 vec3_t nearestpoint;
4823                 vec_t distance;
4824                 int lodlinear;
4825                 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4826                 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4827                 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4828                 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4829                 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4830                 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4831                 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4832                 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4833                 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4834         }
4835 }
4836
4837 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4838 {
4839         int i;
4840         int numsurfaces;
4841         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4842         int numlightentities;
4843         int numlightentities_noselfshadow;
4844         int numshadowentities;
4845         int numshadowentities_noselfshadow;
4846         entity_render_t **lightentities;
4847         entity_render_t **lightentities_noselfshadow;
4848         entity_render_t **shadowentities;
4849         entity_render_t **shadowentities_noselfshadow;
4850         int *surfacelist;
4851         static unsigned char entitysides[MAX_EDICTS];
4852         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4853         float borderbias;
4854         int side;
4855         int size;
4856         int castermask;
4857         int receivermask;
4858         matrix4x4_t radiustolight;
4859
4860         // check if we cached this light this frame (meaning it is worth drawing)
4861         if (!rtlight->draw || !rtlight->castshadows)
4862                 return;
4863
4864         // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4865         if (rtlight->shadowmapatlassidesize == 0)
4866         {
4867                 rtlight->castshadows = false;
4868                 return;
4869         }
4870
4871         // set up a scissor rectangle for this light
4872         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4873                 return;
4874
4875         // don't let sound skip if going slow
4876         if (r_refdef.scene.extraupdate)
4877                 S_ExtraUpdate();
4878
4879         numlightentities = rtlight->cached_numlightentities;
4880         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4881         numshadowentities = rtlight->cached_numshadowentities;
4882         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4883         numsurfaces = rtlight->cached_numsurfaces;
4884         lightentities = rtlight->cached_lightentities;
4885         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4886         shadowentities = rtlight->cached_shadowentities;
4887         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4888         shadowtrispvs = rtlight->cached_shadowtrispvs;
4889         lighttrispvs = rtlight->cached_lighttrispvs;
4890         surfacelist = rtlight->cached_surfacelist;
4891
4892         // make this the active rtlight for rendering purposes
4893         R_Shadow_RenderMode_ActiveLight(rtlight);
4894
4895         radiustolight = rtlight->matrix_worldtolight;
4896         Matrix4x4_Abs(&radiustolight);
4897
4898         size = rtlight->shadowmapatlassidesize;
4899         borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4900
4901         surfacesides = NULL;
4902         castermask = 0;
4903         receivermask = 0;
4904         if (numsurfaces)
4905         {
4906                 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4907                 {
4908                         castermask = rtlight->static_shadowmap_casters;
4909                         receivermask = rtlight->static_shadowmap_receivers;
4910                 }
4911                 else
4912                 {
4913                         surfacesides = r_shadow_buffer_surfacesides;
4914                         for (i = 0; i < numsurfaces; i++)
4915                         {
4916                                 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4917                                 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4918                                 castermask |= surfacesides[i];
4919                                 receivermask |= surfacesides[i];
4920                         }
4921                 }
4922         }
4923
4924         for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4925                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4926         for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4927                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4928
4929         receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4930
4931         if (receivermask)
4932         {
4933                 for (i = 0; i < numshadowentities; i++)
4934                         castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4935                 for (i = 0; i < numshadowentities_noselfshadow; i++)
4936                         castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4937         }
4938
4939         // there is no need to render shadows for sides that have no receivers...
4940         castermask &= receivermask;
4941
4942         //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4943
4944         // render shadow casters into shadowmaps for this light
4945         for (side = 0; side < 6; side++)
4946         {
4947                 int bit = 1 << side;
4948                 if (castermask & bit)
4949                 {
4950                         R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4951                         if (numsurfaces)
4952                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4953                         for (i = 0; i < numshadowentities; i++)
4954                                 if (entitysides[i] & bit)
4955                                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4956                         for (i = 0; i < numshadowentities_noselfshadow; i++)
4957                                 if (entitysides_noselfshadow[i] & bit)
4958                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4959                 }
4960         }
4961         // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4962         if (numshadowentities_noselfshadow)
4963         {
4964                 for (side = 0; side < 6; side++)
4965                 {
4966                         int bit = 1 << side;
4967                         if (castermask & bit)
4968                         {
4969                                 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4970                                 if (numsurfaces)
4971                                         R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4972                                 for (i = 0; i < numshadowentities; i++)
4973                                         if (entitysides[i] & bit)
4974                                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
4975                         }
4976                 }
4977         }
4978 }
4979
4980 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4981 {
4982         int i;
4983         int numsurfaces;
4984         unsigned char *shadowtrispvs, *lighttrispvs;
4985         int numlightentities;
4986         int numlightentities_noselfshadow;
4987         int numshadowentities;
4988         int numshadowentities_noselfshadow;
4989         entity_render_t **lightentities;
4990         entity_render_t **lightentities_noselfshadow;
4991         entity_render_t **shadowentities;
4992         entity_render_t **shadowentities_noselfshadow;
4993         int *surfacelist;
4994         qboolean castshadows;
4995
4996         // check if we cached this light this frame (meaning it is worth drawing)
4997         if (!rtlight->draw)
4998                 return;
4999
5000         // set up a scissor rectangle for this light
5001         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5002                 return;
5003
5004         // don't let sound skip if going slow
5005         if (r_refdef.scene.extraupdate)
5006                 S_ExtraUpdate();
5007
5008         numlightentities = rtlight->cached_numlightentities;
5009         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5010         numshadowentities = rtlight->cached_numshadowentities;
5011         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5012         numsurfaces = rtlight->cached_numsurfaces;
5013         lightentities = rtlight->cached_lightentities;
5014         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5015         shadowentities = rtlight->cached_shadowentities;
5016         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5017         shadowtrispvs = rtlight->cached_shadowtrispvs;
5018         lighttrispvs = rtlight->cached_lighttrispvs;
5019         surfacelist = rtlight->cached_surfacelist;
5020         castshadows = rtlight->castshadows;
5021
5022         // make this the active rtlight for rendering purposes
5023         R_Shadow_RenderMode_ActiveLight(rtlight);
5024
5025         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5026         {
5027                 // optionally draw visible shape of the shadow volumes
5028                 // for performance analysis by level designers
5029                 R_Shadow_RenderMode_VisibleShadowVolumes();
5030                 if (numsurfaces)
5031                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5032                 for (i = 0;i < numshadowentities;i++)
5033                         R_Shadow_DrawEntityShadow(shadowentities[i]);
5034                 for (i = 0;i < numshadowentities_noselfshadow;i++)
5035                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5036                 R_Shadow_RenderMode_VisibleLighting(false, false);
5037         }
5038
5039         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5040         {
5041                 // optionally draw the illuminated areas
5042                 // for performance analysis by level designers
5043                 R_Shadow_RenderMode_VisibleLighting(false, false);
5044                 if (numsurfaces)
5045                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5046                 for (i = 0;i < numlightentities;i++)
5047                         R_Shadow_DrawEntityLight(lightentities[i]);
5048                 for (i = 0;i < numlightentities_noselfshadow;i++)
5049                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5050         }
5051
5052         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5053         {
5054                 float borderbias;
5055                 int size;
5056                 float shadowmapoffsetnoselfshadow = 0;
5057                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5058                 Matrix4x4_Abs(&radiustolight);
5059
5060                 size = rtlight->shadowmapatlassidesize;
5061                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5062
5063                 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5064
5065                 if (rtlight->cached_numshadowentities_noselfshadow)
5066                         shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5067
5068                 // render lighting using the depth texture as shadowmap
5069                 // draw lighting in the unmasked areas
5070                 if (numsurfaces + numlightentities)
5071                 {
5072                         R_Shadow_RenderMode_Lighting(false, false, true, false);
5073                         // draw lighting in the unmasked areas
5074                         if (numsurfaces)
5075                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5076                         for (i = 0; i < numlightentities; i++)
5077                                 R_Shadow_DrawEntityLight(lightentities[i]);
5078                 }
5079                 // offset to the noselfshadow part of the atlas and draw those too
5080                 if (numlightentities_noselfshadow)
5081                 {
5082                         R_Shadow_RenderMode_Lighting(false, false, true, true);
5083                         for (i = 0; i < numlightentities_noselfshadow; i++)
5084                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5085                 }
5086
5087                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5088                 if (r_shadow_usingdeferredprepass)
5089                         R_Shadow_RenderMode_DrawDeferredLight(true);
5090         }
5091         else if (castshadows && vid.stencil)
5092         {
5093                 // draw stencil shadow volumes to mask off pixels that are in shadow
5094                 // so that they won't receive lighting
5095                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5096                 R_Shadow_ClearStencil();
5097
5098                 if (numsurfaces)
5099                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5100                 for (i = 0;i < numshadowentities;i++)
5101                         R_Shadow_DrawEntityShadow(shadowentities[i]);
5102
5103                 // draw lighting in the unmasked areas
5104                 R_Shadow_RenderMode_Lighting(true, false, false, false);
5105                 for (i = 0;i < numlightentities_noselfshadow;i++)
5106                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5107
5108                 for (i = 0;i < numshadowentities_noselfshadow;i++)
5109                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5110
5111                 // draw lighting in the unmasked areas
5112                 R_Shadow_RenderMode_Lighting(true, false, false, false);
5113                 if (numsurfaces)
5114                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5115                 for (i = 0;i < numlightentities;i++)
5116                         R_Shadow_DrawEntityLight(lightentities[i]);
5117
5118                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5119                 if (r_shadow_usingdeferredprepass)
5120                         R_Shadow_RenderMode_DrawDeferredLight(false);
5121         }
5122         else
5123         {
5124                 // draw lighting in the unmasked areas
5125                 R_Shadow_RenderMode_Lighting(false, false, false, false);
5126                 if (numsurfaces)
5127                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5128                 for (i = 0;i < numlightentities;i++)
5129                         R_Shadow_DrawEntityLight(lightentities[i]);
5130                 for (i = 0;i < numlightentities_noselfshadow;i++)
5131                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
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(false);
5136         }
5137 }
5138
5139 static void R_Shadow_FreeDeferred(void)
5140 {
5141         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5142         r_shadow_prepassgeometryfbo = 0;
5143
5144         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5145         r_shadow_prepasslightingdiffusespecularfbo = 0;
5146
5147         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5148         r_shadow_prepasslightingdiffusefbo = 0;
5149
5150         if (r_shadow_prepassgeometrydepthbuffer)
5151                 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5152         r_shadow_prepassgeometrydepthbuffer = NULL;
5153
5154         if (r_shadow_prepassgeometrynormalmaptexture)
5155                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5156         r_shadow_prepassgeometrynormalmaptexture = NULL;
5157
5158         if (r_shadow_prepasslightingdiffusetexture)
5159                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5160         r_shadow_prepasslightingdiffusetexture = NULL;
5161
5162         if (r_shadow_prepasslightingspeculartexture)
5163                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5164         r_shadow_prepasslightingspeculartexture = NULL;
5165 }
5166
5167 void R_Shadow_DrawPrepass(void)
5168 {
5169         int i;
5170         int lnum;
5171         entity_render_t *ent;
5172         float clearcolor[4];
5173
5174         R_Mesh_ResetTextureState();
5175         GL_DepthMask(true);
5176         GL_ColorMask(1,1,1,1);
5177         GL_BlendFunc(GL_ONE, GL_ZERO);
5178         GL_Color(1,1,1,1);
5179         GL_DepthTest(true);
5180         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5181         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5182         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5183         if (r_timereport_active)
5184                 R_TimeReport("prepasscleargeom");
5185
5186         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5187                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5188         if (r_timereport_active)
5189                 R_TimeReport("prepassworld");
5190
5191         for (i = 0;i < r_refdef.scene.numentities;i++)
5192         {
5193                 if (!r_refdef.viewcache.entityvisible[i])
5194                         continue;
5195                 ent = r_refdef.scene.entities[i];
5196                 if (ent->model && ent->model->DrawPrepass != NULL)
5197                         ent->model->DrawPrepass(ent);
5198         }
5199
5200         if (r_timereport_active)
5201                 R_TimeReport("prepassmodels");
5202
5203         GL_DepthMask(false);
5204         GL_ColorMask(1,1,1,1);
5205         GL_Color(1,1,1,1);
5206         GL_DepthTest(true);
5207         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5208         Vector4Set(clearcolor, 0, 0, 0, 0);
5209         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5210         if (r_timereport_active)
5211                 R_TimeReport("prepassclearlit");
5212
5213         R_Shadow_RenderMode_Begin();
5214
5215         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5216                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5217
5218         R_Shadow_RenderMode_End();
5219
5220         if (r_timereport_active)
5221                 R_TimeReport("prepasslights");
5222 }
5223
5224 #define MAX_SCENELIGHTS 65536
5225 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5226 {
5227         if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5228         {
5229                 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5230                         return false;
5231                 r_shadow_scenemaxlights *= 2;
5232                 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5233                 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5234         }
5235         r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5236         return true;
5237 }
5238
5239 void R_Shadow_DrawLightSprites(void);
5240 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5241 {
5242         int flag;
5243         int lnum;
5244         size_t lightindex;
5245         dlight_t *light;
5246         size_t range;
5247         float f;
5248
5249         int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5250         int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5251         int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5252
5253         if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5254                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5255                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5256                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5257                 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5258                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5259                 r_shadow_shadowmapborder != shadowmapborder ||
5260                 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5261                 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5262                 R_Shadow_FreeShadowMaps();
5263
5264         r_shadow_fb_fbo = fbo;
5265         r_shadow_fb_depthtexture = depthtexture;
5266         r_shadow_fb_colortexture = colortexture;
5267
5268         r_shadow_usingshadowmaportho = false;
5269
5270         switch (vid.renderpath)
5271         {
5272         case RENDERPATH_GL20:
5273         case RENDERPATH_D3D9:
5274         case RENDERPATH_D3D10:
5275         case RENDERPATH_D3D11:
5276         case RENDERPATH_SOFT:
5277 #ifndef USE_GLES2
5278                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5279                 {
5280                         r_shadow_usingdeferredprepass = false;
5281                         if (r_shadow_prepass_width)
5282                                 R_Shadow_FreeDeferred();
5283                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
5284                         break;
5285                 }
5286
5287                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5288                 {
5289                         R_Shadow_FreeDeferred();
5290
5291                         r_shadow_usingdeferredprepass = true;
5292                         r_shadow_prepass_width = vid.width;
5293                         r_shadow_prepass_height = vid.height;
5294                         r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5295                         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);
5296                         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);
5297                         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);
5298
5299                         // set up the geometry pass fbo (depth + normalmap)
5300                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5301                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5302                         // render depth into a renderbuffer and other important properties into the normalmap texture
5303
5304                         // set up the lighting pass fbo (diffuse + specular)
5305                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5306                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5307                         // render diffuse into one texture and specular into another,
5308                         // with depth and normalmap bound as textures,
5309                         // with depth bound as attachment as well
5310
5311                         // set up the lighting pass fbo (diffuse)
5312                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5313                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5314                         // render diffuse into one texture,
5315                         // with depth and normalmap bound as textures,
5316                         // with depth bound as attachment as well
5317                 }
5318 #endif
5319                 break;
5320         case RENDERPATH_GL11:
5321         case RENDERPATH_GL13:
5322         case RENDERPATH_GLES1:
5323         case RENDERPATH_GLES2:
5324                 r_shadow_usingdeferredprepass = false;
5325                 break;
5326         }
5327
5328         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);
5329
5330         r_shadow_scenenumlights = 0;
5331         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5332         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5333         for (lightindex = 0; lightindex < range; lightindex++)
5334         {
5335                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5336                 if (light && (light->flags & flag))
5337                 {
5338                         R_Shadow_PrepareLight(&light->rtlight);
5339                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5340                 }
5341         }
5342         if (r_refdef.scene.rtdlight)
5343         {
5344                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5345                 {
5346                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5347                         R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5348                 }
5349         }
5350         else if (gl_flashblend.integer)
5351         {
5352                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5353                 {
5354                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5355                         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5356                         VectorScale(rtlight->color, f, rtlight->currentcolor);
5357                 }
5358         }
5359
5360         // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5361         if (r_shadow_debuglight.integer >= 0)
5362         {
5363                 r_shadow_scenenumlights = 0;
5364                 lightindex = r_shadow_debuglight.integer;
5365                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5366                 if (light)
5367                 {
5368                         R_Shadow_PrepareLight(&light->rtlight);
5369                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5370                 }
5371         }
5372
5373         // if we're doing shadowmaps we need to prepare the atlas layout now
5374         if (R_Shadow_ShadowMappingEnabled())
5375         {
5376                 int lod;
5377
5378                 // allocate shadowmaps in the atlas now
5379                 // 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...
5380                 for (lod = 0; lod < 16; lod++)
5381                 {
5382                         int packing_success = 0;
5383                         int packing_failure = 0;
5384                         Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5385                         // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5386                         if (r_shadow_shadowmapatlas_modelshadows_size)
5387                                 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);
5388                         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5389                         {
5390                                 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5391                                 int size = rtlight->shadowmapsidesize >> lod;
5392                                 int width, height;
5393                                 if (!rtlight->castshadows)
5394                                         continue;
5395                                 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5396                                 width = size * 2;
5397                                 height = size * 3;
5398                                 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5399                                 if (rtlight->cached_numshadowentities_noselfshadow)
5400                                         width *= 2;
5401                                 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5402                                 {
5403                                         rtlight->shadowmapatlassidesize = size;
5404                                         packing_success++;
5405                                 }
5406                                 else
5407                                 {
5408                                         // note down that we failed to pack this one, it will have to disable shadows
5409                                         rtlight->shadowmapatlassidesize = 0;
5410                                         packing_failure++;
5411                                 }
5412                         }
5413                         // generally everything fits and we stop here on the first iteration
5414                         if (packing_failure == 0)
5415                                 break;
5416                 }
5417         }
5418
5419         if (r_editlights.integer)
5420                 R_Shadow_DrawLightSprites();
5421 }
5422
5423 void R_Shadow_DrawShadowMaps(void)
5424 {
5425         R_Shadow_RenderMode_Begin();
5426         R_Shadow_RenderMode_ActiveLight(NULL);
5427
5428         // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5429         R_Shadow_ClearShadowMapTexture();
5430
5431         // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5432         if (r_shadow_shadowmapatlas_modelshadows_size)
5433         {
5434                 R_Shadow_DrawModelShadowMaps();
5435                 // don't let sound skip if going slow
5436                 if (r_refdef.scene.extraupdate)
5437                         S_ExtraUpdate();
5438         }
5439
5440         if (R_Shadow_ShadowMappingEnabled())
5441         {
5442                 int lnum;
5443                 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5444                         R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5445         }
5446
5447         R_Shadow_RenderMode_End();
5448 }
5449
5450 void R_Shadow_DrawLights(void)
5451 {
5452         int lnum;
5453
5454         R_Shadow_RenderMode_Begin();
5455
5456         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5457                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5458
5459         R_Shadow_RenderMode_End();
5460 }
5461
5462 #define MAX_MODELSHADOWS 1024
5463 static int r_shadow_nummodelshadows;
5464 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5465
5466 void R_Shadow_PrepareModelShadows(void)
5467 {
5468         int i;
5469         float scale, size, radius, dot1, dot2;
5470         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5471         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5472         entity_render_t *ent;
5473
5474         r_shadow_nummodelshadows = 0;
5475         r_shadow_shadowmapatlas_modelshadows_size = 0;
5476
5477         if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5478                 return;
5479
5480         switch (r_shadow_shadowmode)
5481         {
5482         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5483                 if (r_shadows.integer >= 2)
5484                         break;
5485                 // fall through
5486         case R_SHADOW_SHADOWMODE_STENCIL:
5487                 if (!vid.stencil)
5488                         return;
5489                 for (i = 0; i < r_refdef.scene.numentities; i++)
5490                 {
5491                         ent = r_refdef.scene.entities[i];
5492                         if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5493                         {
5494                                 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5495                                         break;
5496                                 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5497                                 R_AnimCache_GetEntity(ent, false, false);
5498                         }
5499                 }
5500                 return;
5501         default:
5502                 return;
5503         }
5504
5505         size = 2 * r_shadow_shadowmapmaxsize;
5506         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5507         radius = 0.5f * size / scale;
5508
5509         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5510         VectorCopy(prvmshadowdir, shadowdir);
5511         VectorNormalize(shadowdir);
5512         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5513         dot2 = DotProduct(r_refdef.view.up, shadowdir);
5514         if (fabs(dot1) <= fabs(dot2))
5515                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5516         else
5517                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5518         VectorNormalize(shadowforward);
5519         CrossProduct(shadowdir, shadowforward, shadowright);
5520         Math_atov(r_shadows_focus.string, prvmshadowfocus);
5521         VectorCopy(prvmshadowfocus, shadowfocus);
5522         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5523         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5524         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5525         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5526         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5527                 dot1 = 1;
5528         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5529
5530         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5531         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5532         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5533         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5534         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5535         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5536
5537         for (i = 0; i < r_refdef.scene.numentities; i++)
5538         {
5539                 ent = r_refdef.scene.entities[i];
5540                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5541                         continue;
5542                 // cast shadows from anything of the map (submodels are optional)
5543                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5544                 {
5545                         if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5546                                 break;
5547                         r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5548                         R_AnimCache_GetEntity(ent, false, false);
5549                 }
5550         }
5551
5552         if (r_shadow_nummodelshadows)
5553         {
5554                 r_shadow_shadowmapatlas_modelshadows_x = 0;
5555                 r_shadow_shadowmapatlas_modelshadows_y = 0;
5556                 r_shadow_shadowmapatlas_modelshadows_size = size;
5557         }
5558 }
5559
5560 static void R_Shadow_DrawModelShadowMaps(void)
5561 {
5562         int i;
5563         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5564         entity_render_t *ent;
5565         vec3_t relativelightorigin;
5566         vec3_t relativelightdirection, relativeforward, relativeright;
5567         vec3_t relativeshadowmins, relativeshadowmaxs;
5568         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5569         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5570         float m[12];
5571         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5572         r_viewport_t viewport;
5573
5574         size = r_shadow_shadowmapatlas_modelshadows_size;
5575         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5576         radius = 0.5f / scale;
5577         nearclip = -r_shadows_throwdistance.value;
5578         farclip = r_shadows_throwdistance.value;
5579         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);
5580
5581         // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5582         r_shadow_modelshadowmap_parameters[0] = size;
5583         r_shadow_modelshadowmap_parameters[1] = size;
5584         r_shadow_modelshadowmap_parameters[2] = 1.0;
5585         r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5586         r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5587         r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5588         r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5589         r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5590         r_shadow_usingshadowmaportho = true;
5591
5592         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5593         VectorCopy(prvmshadowdir, shadowdir);
5594         VectorNormalize(shadowdir);
5595         Math_atov(r_shadows_focus.string, prvmshadowfocus);
5596         VectorCopy(prvmshadowfocus, shadowfocus);
5597         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5598         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5599         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5600         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5601         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5602         dot2 = DotProduct(r_refdef.view.up, shadowdir);
5603         if (fabs(dot1) <= fabs(dot2)) 
5604                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5605         else
5606                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5607         VectorNormalize(shadowforward);
5608         VectorM(scale, shadowforward, &m[0]);
5609         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5610                 dot1 = 1;
5611         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5612         CrossProduct(shadowdir, shadowforward, shadowright);
5613         VectorM(scale, shadowright, &m[4]);
5614         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5615         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5616         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5617         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5618         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5619         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);
5620         R_SetViewport(&viewport);
5621
5622         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5623
5624         // render into a slightly restricted region so that the borders of the
5625         // shadowmap area fade away, rather than streaking across everything
5626         // outside the usable area
5627         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5628
5629         for (i = 0;i < r_shadow_nummodelshadows;i++)
5630         {
5631                 ent = r_shadow_modelshadows[i];
5632                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5633                 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5634                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5635                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5636                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5637                 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5638                 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5639                 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5640                 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5641                 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5642                 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5643                 RSurf_ActiveModelEntity(ent, false, false, false);
5644                 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5645                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5646         }
5647
5648 #if 0
5649         if (r_test.integer)
5650         {
5651                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5652                 CHECKGLERROR
5653                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5654                 CHECKGLERROR
5655                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5656                 Cvar_SetValueQuick(&r_test, 0);
5657                 Z_Free(rawpixels);
5658         }
5659 #endif
5660
5661         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5662         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5663         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
5664         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5665         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5666         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5667
5668         switch (vid.renderpath)
5669         {
5670         case RENDERPATH_GL11:
5671         case RENDERPATH_GL13:
5672         case RENDERPATH_GL20:
5673         case RENDERPATH_SOFT:
5674         case RENDERPATH_GLES1:
5675         case RENDERPATH_GLES2:
5676                 break;
5677         case RENDERPATH_D3D9:
5678         case RENDERPATH_D3D10:
5679         case RENDERPATH_D3D11:
5680 #ifdef MATRIX4x4_OPENGLORIENTATION
5681                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
5682                 r_shadow_shadowmapmatrix.m[0][1]        *= -1.0f;
5683                 r_shadow_shadowmapmatrix.m[0][2]        *= -1.0f;
5684                 r_shadow_shadowmapmatrix.m[0][3]        *= -1.0f;
5685 #else
5686                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
5687                 r_shadow_shadowmapmatrix.m[1][0]        *= -1.0f;
5688                 r_shadow_shadowmapmatrix.m[2][0]        *= -1.0f;
5689                 r_shadow_shadowmapmatrix.m[3][0]        *= -1.0f;
5690 #endif
5691                 break;
5692         }
5693 }
5694
5695 void R_Shadow_DrawModelShadows(void)
5696 {
5697         int i;
5698         float relativethrowdistance;
5699         entity_render_t *ent;
5700         vec3_t relativelightorigin;
5701         vec3_t relativelightdirection;
5702         vec3_t relativeshadowmins, relativeshadowmaxs;
5703         vec3_t tmp, shadowdir;
5704         prvm_vec3_t prvmshadowdir;
5705
5706         if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5707                 return;
5708
5709         R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5710         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5711         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5712         R_Shadow_RenderMode_Begin();
5713         R_Shadow_RenderMode_ActiveLight(NULL);
5714         r_shadow_lightscissor[0] = r_refdef.view.x;
5715         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5716         r_shadow_lightscissor[2] = r_refdef.view.width;
5717         r_shadow_lightscissor[3] = r_refdef.view.height;
5718         R_Shadow_RenderMode_StencilShadowVolumes(false);
5719
5720         // get shadow dir
5721         if (r_shadows.integer == 2)
5722         {
5723                 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5724                 VectorCopy(prvmshadowdir, shadowdir);
5725                 VectorNormalize(shadowdir);
5726         }
5727
5728         R_Shadow_ClearStencil();
5729
5730         for (i = 0;i < r_shadow_nummodelshadows;i++)
5731         {
5732                 ent = r_shadow_modelshadows[i];
5733
5734                 // cast shadows from anything of the map (submodels are optional)
5735                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5736                 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5737                 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5738                 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5739                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5740                 else
5741                 {
5742                         if(ent->entitynumber != 0)
5743                         {
5744                                 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5745                                 {
5746                                         // FIXME handle this
5747                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
5748                                 }
5749                                 else
5750                                 {
5751                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5752                                         int entnum, entnum2, recursion;
5753                                         entnum = entnum2 = ent->entitynumber;
5754                                         for(recursion = 32; recursion > 0; --recursion)
5755                                         {
5756                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
5757                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5758                                                         entnum = entnum2;
5759                                                 else
5760                                                         break;
5761                                         }
5762                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5763                                         {
5764                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5765                                                 // transform into modelspace of OUR entity
5766                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5767                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5768                                         }
5769                                         else
5770                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5771                                 }
5772                         }
5773                         else
5774                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5775                 }
5776
5777                 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5778                 RSurf_ActiveModelEntity(ent, false, false, false);
5779                 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5780                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5781         }
5782
5783         // not really the right mode, but this will disable any silly stencil features
5784         R_Shadow_RenderMode_End();
5785
5786         // set up ortho view for rendering this pass
5787         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5788         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5789         //GL_ScissorTest(true);
5790         //R_EntityMatrix(&identitymatrix);
5791         //R_Mesh_ResetTextureState();
5792         R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5793
5794         // set up a darkening blend on shadowed areas
5795         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5796         //GL_DepthRange(0, 1);
5797         //GL_DepthTest(false);
5798         //GL_DepthMask(false);
5799         //GL_PolygonOffset(0, 0);CHECKGLERROR
5800         GL_Color(0, 0, 0, r_shadows_darken.value);
5801         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5802         //GL_DepthFunc(GL_ALWAYS);
5803         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5804
5805         // apply the blend to the shadowed areas
5806         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5807         R_SetupShader_Generic_NoTexture(false, true);
5808         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5809
5810         // restore the viewport
5811         R_SetViewport(&r_refdef.view.viewport);
5812
5813         // restore other state to normal
5814         //R_Shadow_RenderMode_End();
5815 }
5816
5817 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5818 {
5819         float zdist;
5820         vec3_t centerorigin;
5821 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5822         float vertex3f[12];
5823 #endif
5824         // if it's too close, skip it
5825         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5826                 return;
5827         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5828         if (zdist < 32)
5829                 return;
5830         if (usequery && r_numqueries + 2 <= r_maxqueries)
5831         {
5832                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5833                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5834                 // 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
5835                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5836
5837                 switch(vid.renderpath)
5838                 {
5839                 case RENDERPATH_GL11:
5840                 case RENDERPATH_GL13:
5841                 case RENDERPATH_GL20:
5842                 case RENDERPATH_GLES1:
5843                 case RENDERPATH_GLES2:
5844 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5845                         CHECKGLERROR
5846                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5847                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5848                         GL_DepthFunc(GL_ALWAYS);
5849                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5850                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5851                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5852                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5853                         GL_DepthFunc(GL_LEQUAL);
5854                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5855                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5856                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5857                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5858                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5859                         CHECKGLERROR
5860 #endif
5861                         break;
5862                 case RENDERPATH_D3D9:
5863                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5864                         break;
5865                 case RENDERPATH_D3D10:
5866                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5867                         break;
5868                 case RENDERPATH_D3D11:
5869                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5870                         break;
5871                 case RENDERPATH_SOFT:
5872                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5873                         break;
5874                 }
5875         }
5876         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5877 }
5878
5879 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5880
5881 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5882 {
5883         vec3_t color;
5884         unsigned int occlude = 0;
5885         GLint allpixels = 0, visiblepixels = 0;
5886
5887         // now we have to check the query result
5888         if (rtlight->corona_queryindex_visiblepixels)
5889         {
5890                 switch(vid.renderpath)
5891                 {
5892                 case RENDERPATH_GL11:
5893                 case RENDERPATH_GL13:
5894                 case RENDERPATH_GL20:
5895                 case RENDERPATH_GLES1:
5896                 case RENDERPATH_GLES2:
5897 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5898                         CHECKGLERROR
5899                         // See if we can use the GPU-side method to prevent implicit sync
5900                         if (vid.support.arb_query_buffer_object) {
5901 #define BUFFER_OFFSET(i)    ((GLint *)((unsigned char*)NULL + (i)))
5902                                 if (!r_shadow_occlusion_buf) {
5903                                         qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5904                                         qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5905                                         qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5906                                 } else {
5907                                         qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5908                                 }
5909                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5910                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5911                                 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5912                                 occlude = MATERIALFLAG_OCCLUDE;
5913                         } else {
5914                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5915                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels); 
5916                                 if (visiblepixels < 1 || allpixels < 1)
5917                                         return;
5918                                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5919                         }
5920                         cscale *= rtlight->corona_visibility;
5921                         CHECKGLERROR
5922                         break;
5923 #else
5924                         return;
5925 #endif
5926                 case RENDERPATH_D3D9:
5927                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5928                         return;
5929                 case RENDERPATH_D3D10:
5930                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5931                         return;
5932                 case RENDERPATH_D3D11:
5933                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5934                         return;
5935                 case RENDERPATH_SOFT:
5936                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5937                         return;
5938                 default:
5939                         return;
5940                 }
5941         }
5942         else
5943         {
5944                 // FIXME: these traces should scan all render entities instead of cl.world
5945                 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)
5946                         return;
5947         }
5948         VectorScale(rtlight->currentcolor, cscale, color);
5949         if (VectorLength(color) > (1.0f / 256.0f))
5950         {
5951                 float vertex3f[12];
5952                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5953                 if(negated)
5954                 {
5955                         VectorNegate(color, color);
5956                         GL_BlendEquationSubtract(true);
5957                 }
5958                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5959                 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);
5960                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5961                 if(negated)
5962                         GL_BlendEquationSubtract(false);
5963         }
5964 }
5965
5966 void R_Shadow_DrawCoronas(void)
5967 {
5968         int i, flag;
5969         qboolean usequery = false;
5970         size_t lightindex;
5971         dlight_t *light;
5972         rtlight_t *rtlight;
5973         size_t range;
5974         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5975                 return;
5976         if (r_fb.water.renderingscene)
5977                 return;
5978         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5979         R_EntityMatrix(&identitymatrix);
5980
5981         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5982
5983         // check occlusion of coronas
5984         // use GL_ARB_occlusion_query if available
5985         // otherwise use raytraces
5986         r_numqueries = 0;
5987         switch (vid.renderpath)
5988         {
5989         case RENDERPATH_GL11:
5990         case RENDERPATH_GL13:
5991         case RENDERPATH_GL20:
5992         case RENDERPATH_GLES1:
5993         case RENDERPATH_GLES2:
5994                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5995 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5996                 if (usequery)
5997                 {
5998                         GL_ColorMask(0,0,0,0);
5999                         if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6000                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6001                         {
6002                                 i = r_maxqueries;
6003                                 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6004                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6005                                 CHECKGLERROR
6006                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6007                                 CHECKGLERROR
6008                         }
6009                         RSurf_ActiveWorldEntity();
6010                         GL_BlendFunc(GL_ONE, GL_ZERO);
6011                         GL_CullFace(GL_NONE);
6012                         GL_DepthMask(false);
6013                         GL_DepthRange(0, 1);
6014                         GL_PolygonOffset(0, 0);
6015                         GL_DepthTest(true);
6016                         R_Mesh_ResetTextureState();
6017                         R_SetupShader_Generic_NoTexture(false, false);
6018                 }
6019 #endif
6020                 break;
6021         case RENDERPATH_D3D9:
6022                 usequery = false;
6023                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6024                 break;
6025         case RENDERPATH_D3D10:
6026                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6027                 break;
6028         case RENDERPATH_D3D11:
6029                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6030                 break;
6031         case RENDERPATH_SOFT:
6032                 usequery = false;
6033                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6034                 break;
6035         }
6036         for (lightindex = 0;lightindex < range;lightindex++)
6037         {
6038                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6039                 if (!light)
6040                         continue;
6041                 rtlight = &light->rtlight;
6042                 rtlight->corona_visibility = 0;
6043                 rtlight->corona_queryindex_visiblepixels = 0;
6044                 rtlight->corona_queryindex_allpixels = 0;
6045                 if (!(rtlight->flags & flag))
6046                         continue;
6047                 if (rtlight->corona <= 0)
6048                         continue;
6049                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6050                         continue;
6051                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6052         }
6053         for (i = 0;i < r_refdef.scene.numlights;i++)
6054         {
6055                 rtlight = r_refdef.scene.lights[i];
6056                 rtlight->corona_visibility = 0;
6057                 rtlight->corona_queryindex_visiblepixels = 0;
6058                 rtlight->corona_queryindex_allpixels = 0;
6059                 if (!(rtlight->flags & flag))
6060                         continue;
6061                 if (rtlight->corona <= 0)
6062                         continue;
6063                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6064         }
6065         if (usequery)
6066                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6067
6068         // now draw the coronas using the query data for intensity info
6069         for (lightindex = 0;lightindex < range;lightindex++)
6070         {
6071                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6072                 if (!light)
6073                         continue;
6074                 rtlight = &light->rtlight;
6075                 if (rtlight->corona_visibility <= 0)
6076                         continue;
6077                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6078         }
6079         for (i = 0;i < r_refdef.scene.numlights;i++)
6080         {
6081                 rtlight = r_refdef.scene.lights[i];
6082                 if (rtlight->corona_visibility <= 0)
6083                         continue;
6084                 if (gl_flashblend.integer)
6085                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6086                 else
6087                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6088         }
6089 }
6090
6091
6092
6093 static dlight_t *R_Shadow_NewWorldLight(void)
6094 {
6095         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6096 }
6097
6098 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)
6099 {
6100         matrix4x4_t matrix;
6101
6102         // 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
6103
6104         // validate parameters
6105         if (!cubemapname)
6106                 cubemapname = "";
6107
6108         // copy to light properties
6109         VectorCopy(origin, light->origin);
6110         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6111         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6112         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6113         /*
6114         light->color[0] = max(color[0], 0);
6115         light->color[1] = max(color[1], 0);
6116         light->color[2] = max(color[2], 0);
6117         */
6118         light->color[0] = color[0];
6119         light->color[1] = color[1];
6120         light->color[2] = color[2];
6121         light->radius = max(radius, 0);
6122         light->style = style;
6123         light->shadow = shadowenable;
6124         light->corona = corona;
6125         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6126         light->coronasizescale = coronasizescale;
6127         light->ambientscale = ambientscale;
6128         light->diffusescale = diffusescale;
6129         light->specularscale = specularscale;
6130         light->flags = flags;
6131
6132         // update renderable light data
6133         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6134         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);
6135 }
6136
6137 static void R_Shadow_FreeWorldLight(dlight_t *light)
6138 {
6139         if (r_shadow_selectedlight == light)
6140                 r_shadow_selectedlight = NULL;
6141         R_RTLight_Uncompile(&light->rtlight);
6142         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6143 }
6144
6145 void R_Shadow_ClearWorldLights(void)
6146 {
6147         size_t lightindex;
6148         dlight_t *light;
6149         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6150         for (lightindex = 0;lightindex < range;lightindex++)
6151         {
6152                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6153                 if (light)
6154                         R_Shadow_FreeWorldLight(light);
6155         }
6156         r_shadow_selectedlight = NULL;
6157 }
6158
6159 static void R_Shadow_SelectLight(dlight_t *light)
6160 {
6161         if (r_shadow_selectedlight)
6162                 r_shadow_selectedlight->selected = false;
6163         r_shadow_selectedlight = light;
6164         if (r_shadow_selectedlight)
6165                 r_shadow_selectedlight->selected = true;
6166 }
6167
6168 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6169 {
6170         // this is never batched (there can be only one)
6171         float vertex3f[12];
6172         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6173         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6174         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6175 }
6176
6177 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6178 {
6179         float intensity;
6180         float s;
6181         vec3_t spritecolor;
6182         skinframe_t *skinframe;
6183         float vertex3f[12];
6184
6185         // this is never batched (due to the ent parameter changing every time)
6186         // so numsurfaces == 1 and surfacelist[0] == lightnumber
6187         const dlight_t *light = (dlight_t *)ent;
6188         s = EDLIGHTSPRSIZE;
6189
6190         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6191
6192         intensity = 0.5f;
6193         VectorScale(light->color, intensity, spritecolor);
6194         if (VectorLength(spritecolor) < 0.1732f)
6195                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6196         if (VectorLength(spritecolor) > 1.0f)
6197                 VectorNormalize(spritecolor);
6198
6199         // draw light sprite
6200         if (light->cubemapname[0] && !light->shadow)
6201                 skinframe = r_editlights_sprcubemapnoshadowlight;
6202         else if (light->cubemapname[0])
6203                 skinframe = r_editlights_sprcubemaplight;
6204         else if (!light->shadow)
6205                 skinframe = r_editlights_sprnoshadowlight;
6206         else
6207                 skinframe = r_editlights_sprlight;
6208
6209         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);
6210         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6211
6212         // draw selection sprite if light is selected
6213         if (light->selected)
6214         {
6215                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6216                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6217                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6218         }
6219 }
6220
6221 void R_Shadow_DrawLightSprites(void)
6222 {
6223         size_t lightindex;
6224         dlight_t *light;
6225         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6226         for (lightindex = 0;lightindex < range;lightindex++)
6227         {
6228                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6229                 if (light)
6230                         R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6231         }
6232         if (!r_editlights_lockcursor)
6233                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6234 }
6235
6236 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6237 {
6238         unsigned int range;
6239         dlight_t *light;
6240         rtlight_t *rtlight;
6241         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6242         if (lightindex >= range)
6243                 return -1;
6244         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6245         if (!light)
6246                 return 0;
6247         rtlight = &light->rtlight;
6248         //if (!(rtlight->flags & flag))
6249         //      return 0;
6250         VectorCopy(rtlight->shadoworigin, origin);
6251         *radius = rtlight->radius;
6252         VectorCopy(rtlight->color, color);
6253         return 1;
6254 }
6255
6256 static void R_Shadow_SelectLightInView(void)
6257 {
6258         float bestrating, rating, temp[3];
6259         dlight_t *best;
6260         size_t lightindex;
6261         dlight_t *light;
6262         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6263         best = NULL;
6264         bestrating = 0;
6265
6266         if (r_editlights_lockcursor)
6267                 return;
6268         for (lightindex = 0;lightindex < range;lightindex++)
6269         {
6270                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6271                 if (!light)
6272                         continue;
6273                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6274                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6275                 if (rating >= 0.95)
6276                 {
6277                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6278                         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)
6279                         {
6280                                 bestrating = rating;
6281                                 best = light;
6282                         }
6283                 }
6284         }
6285         R_Shadow_SelectLight(best);
6286 }
6287
6288 void R_Shadow_LoadWorldLights(void)
6289 {
6290         int n, a, style, shadow, flags;
6291         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6292         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6293         if (cl.worldmodel == NULL)
6294         {
6295                 Con_Print("No map loaded.\n");
6296                 return;
6297         }
6298         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6299         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6300         if (lightsstring)
6301         {
6302                 s = lightsstring;
6303                 n = 0;
6304                 while (*s)
6305                 {
6306                         /*
6307                         t = s;
6308                         shadow = true;
6309                         for (;COM_Parse(t, true) && strcmp(
6310                         if (COM_Parse(t, true))
6311                         {
6312                                 if (com_token[0] == '!')
6313                                 {
6314                                         shadow = false;
6315                                         origin[0] = atof(com_token+1);
6316                                 }
6317                                 else
6318                                         origin[0] = atof(com_token);
6319                                 if (Com_Parse(t
6320                         }
6321                         */
6322                         t = s;
6323                         while (*s && *s != '\n' && *s != '\r')
6324                                 s++;
6325                         if (!*s)
6326                                 break;
6327                         tempchar = *s;
6328                         shadow = true;
6329                         // check for modifier flags
6330                         if (*t == '!')
6331                         {
6332                                 shadow = false;
6333                                 t++;
6334                         }
6335                         *s = 0;
6336 #if _MSC_VER >= 1400
6337 #define sscanf sscanf_s
6338 #endif
6339                         cubemapname[sizeof(cubemapname)-1] = 0;
6340 #if MAX_QPATH != 128
6341 #error update this code if MAX_QPATH changes
6342 #endif
6343                         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
6344 #if _MSC_VER >= 1400
6345 , sizeof(cubemapname)
6346 #endif
6347 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6348                         *s = tempchar;
6349                         if (a < 18)
6350                                 flags = LIGHTFLAG_REALTIMEMODE;
6351                         if (a < 17)
6352                                 specularscale = 1;
6353                         if (a < 16)
6354                                 diffusescale = 1;
6355                         if (a < 15)
6356                                 ambientscale = 0;
6357                         if (a < 14)
6358                                 coronasizescale = 0.25f;
6359                         if (a < 13)
6360                                 VectorClear(angles);
6361                         if (a < 10)
6362                                 corona = 0;
6363                         if (a < 9 || !strcmp(cubemapname, "\"\""))
6364                                 cubemapname[0] = 0;
6365                         // remove quotes on cubemapname
6366                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6367                         {
6368                                 size_t namelen;
6369                                 namelen = strlen(cubemapname) - 2;
6370                                 memmove(cubemapname, cubemapname + 1, namelen);
6371                                 cubemapname[namelen] = '\0';
6372                         }
6373                         if (a < 8)
6374                         {
6375                                 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);
6376                                 break;
6377                         }
6378                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6379                         if (*s == '\r')
6380                                 s++;
6381                         if (*s == '\n')
6382                                 s++;
6383                         n++;
6384                 }
6385                 if (*s)
6386                         Con_Printf("invalid rtlights file \"%s\"\n", name);
6387                 Mem_Free(lightsstring);
6388         }
6389 }
6390
6391 void R_Shadow_SaveWorldLights(void)
6392 {
6393         size_t lightindex;
6394         dlight_t *light;
6395         size_t bufchars, bufmaxchars;
6396         char *buf, *oldbuf;
6397         char name[MAX_QPATH];
6398         char line[MAX_INPUTLINE];
6399         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6400         // I hate lines which are 3 times my screen size :( --blub
6401         if (!range)
6402                 return;
6403         if (cl.worldmodel == NULL)
6404         {
6405                 Con_Print("No map loaded.\n");
6406                 return;
6407         }
6408         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6409         bufchars = bufmaxchars = 0;
6410         buf = NULL;
6411         for (lightindex = 0;lightindex < range;lightindex++)
6412         {
6413                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6414                 if (!light)
6415                         continue;
6416                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6417                         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);
6418                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6419                         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]);
6420                 else
6421                         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);
6422                 if (bufchars + strlen(line) > bufmaxchars)
6423                 {
6424                         bufmaxchars = bufchars + strlen(line) + 2048;
6425                         oldbuf = buf;
6426                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6427                         if (oldbuf)
6428                         {
6429                                 if (bufchars)
6430                                         memcpy(buf, oldbuf, bufchars);
6431                                 Mem_Free(oldbuf);
6432                         }
6433                 }
6434                 if (strlen(line))
6435                 {
6436                         memcpy(buf + bufchars, line, strlen(line));
6437                         bufchars += strlen(line);
6438                 }
6439         }
6440         if (bufchars)
6441                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6442         if (buf)
6443                 Mem_Free(buf);
6444 }
6445
6446 void R_Shadow_LoadLightsFile(void)
6447 {
6448         int n, a, style;
6449         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6450         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6451         if (cl.worldmodel == NULL)
6452         {
6453                 Con_Print("No map loaded.\n");
6454                 return;
6455         }
6456         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6457         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6458         if (lightsstring)
6459         {
6460                 s = lightsstring;
6461                 n = 0;
6462                 while (*s)
6463                 {
6464                         t = s;
6465                         while (*s && *s != '\n' && *s != '\r')
6466                                 s++;
6467                         if (!*s)
6468                                 break;
6469                         tempchar = *s;
6470                         *s = 0;
6471                         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);
6472                         *s = tempchar;
6473                         if (a < 14)
6474                         {
6475                                 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);
6476                                 break;
6477                         }
6478                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6479                         radius = bound(15, radius, 4096);
6480                         VectorScale(color, (2.0f / (8388608.0f)), color);
6481                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6482                         if (*s == '\r')
6483                                 s++;
6484                         if (*s == '\n')
6485                                 s++;
6486                         n++;
6487                 }
6488                 if (*s)
6489                         Con_Printf("invalid lights file \"%s\"\n", name);
6490                 Mem_Free(lightsstring);
6491         }
6492 }
6493
6494 // tyrlite/hmap2 light types in the delay field
6495 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6496
6497 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6498 {
6499         int entnum;
6500         int style;
6501         int islight;
6502         int skin;
6503         int pflags;
6504         //int effects;
6505         int type;
6506         int n;
6507         char *entfiledata;
6508         const char *data;
6509         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6510         char key[256], value[MAX_INPUTLINE];
6511         char vabuf[1024];
6512
6513         if (cl.worldmodel == NULL)
6514         {
6515                 Con_Print("No map loaded.\n");
6516                 return;
6517         }
6518         // try to load a .ent file first
6519         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6520         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6521         // and if that is not found, fall back to the bsp file entity string
6522         if (!data)
6523                 data = cl.worldmodel->brush.entities;
6524         if (!data)
6525                 return;
6526         for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6527         {
6528                 type = LIGHTTYPE_MINUSX;
6529                 origin[0] = origin[1] = origin[2] = 0;
6530                 originhack[0] = originhack[1] = originhack[2] = 0;
6531                 angles[0] = angles[1] = angles[2] = 0;
6532                 color[0] = color[1] = color[2] = 1;
6533                 light[0] = light[1] = light[2] = 1;light[3] = 300;
6534                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6535                 fadescale = 1;
6536                 lightscale = 1;
6537                 style = 0;
6538                 skin = 0;
6539                 pflags = 0;
6540                 //effects = 0;
6541                 islight = false;
6542                 while (1)
6543                 {
6544                         if (!COM_ParseToken_Simple(&data, false, false, true))
6545                                 break; // error
6546                         if (com_token[0] == '}')
6547                                 break; // end of entity
6548                         if (com_token[0] == '_')
6549                                 strlcpy(key, com_token + 1, sizeof(key));
6550                         else
6551                                 strlcpy(key, com_token, sizeof(key));
6552                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
6553                                 key[strlen(key)-1] = 0;
6554                         if (!COM_ParseToken_Simple(&data, false, false, true))
6555                                 break; // error
6556                         strlcpy(value, com_token, sizeof(value));
6557
6558                         // now that we have the key pair worked out...
6559                         if (!strcmp("light", key))
6560                         {
6561                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6562                                 if (n == 1)
6563                                 {
6564                                         // quake
6565                                         light[0] = vec[0] * (1.0f / 256.0f);
6566                                         light[1] = vec[0] * (1.0f / 256.0f);
6567                                         light[2] = vec[0] * (1.0f / 256.0f);
6568                                         light[3] = vec[0];
6569                                 }
6570                                 else if (n == 4)
6571                                 {
6572                                         // halflife
6573                                         light[0] = vec[0] * (1.0f / 255.0f);
6574                                         light[1] = vec[1] * (1.0f / 255.0f);
6575                                         light[2] = vec[2] * (1.0f / 255.0f);
6576                                         light[3] = vec[3];
6577                                 }
6578                         }
6579                         else if (!strcmp("delay", key))
6580                                 type = atoi(value);
6581                         else if (!strcmp("origin", key))
6582                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6583                         else if (!strcmp("angle", key))
6584                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6585                         else if (!strcmp("angles", key))
6586                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6587                         else if (!strcmp("color", key))
6588                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6589                         else if (!strcmp("wait", key))
6590                                 fadescale = atof(value);
6591                         else if (!strcmp("classname", key))
6592                         {
6593                                 if (!strncmp(value, "light", 5))
6594                                 {
6595                                         islight = true;
6596                                         if (!strcmp(value, "light_fluoro"))
6597                                         {
6598                                                 originhack[0] = 0;
6599                                                 originhack[1] = 0;
6600                                                 originhack[2] = 0;
6601                                                 overridecolor[0] = 1;
6602                                                 overridecolor[1] = 1;
6603                                                 overridecolor[2] = 1;
6604                                         }
6605                                         if (!strcmp(value, "light_fluorospark"))
6606                                         {
6607                                                 originhack[0] = 0;
6608                                                 originhack[1] = 0;
6609                                                 originhack[2] = 0;
6610                                                 overridecolor[0] = 1;
6611                                                 overridecolor[1] = 1;
6612                                                 overridecolor[2] = 1;
6613                                         }
6614                                         if (!strcmp(value, "light_globe"))
6615                                         {
6616                                                 originhack[0] = 0;
6617                                                 originhack[1] = 0;
6618                                                 originhack[2] = 0;
6619                                                 overridecolor[0] = 1;
6620                                                 overridecolor[1] = 0.8;
6621                                                 overridecolor[2] = 0.4;
6622                                         }
6623                                         if (!strcmp(value, "light_flame_large_yellow"))
6624                                         {
6625                                                 originhack[0] = 0;
6626                                                 originhack[1] = 0;
6627                                                 originhack[2] = 0;
6628                                                 overridecolor[0] = 1;
6629                                                 overridecolor[1] = 0.5;
6630                                                 overridecolor[2] = 0.1;
6631                                         }
6632                                         if (!strcmp(value, "light_flame_small_yellow"))
6633                                         {
6634                                                 originhack[0] = 0;
6635                                                 originhack[1] = 0;
6636                                                 originhack[2] = 0;
6637                                                 overridecolor[0] = 1;
6638                                                 overridecolor[1] = 0.5;
6639                                                 overridecolor[2] = 0.1;
6640                                         }
6641                                         if (!strcmp(value, "light_torch_small_white"))
6642                                         {
6643                                                 originhack[0] = 0;
6644                                                 originhack[1] = 0;
6645                                                 originhack[2] = 0;
6646                                                 overridecolor[0] = 1;
6647                                                 overridecolor[1] = 0.5;
6648                                                 overridecolor[2] = 0.1;
6649                                         }
6650                                         if (!strcmp(value, "light_torch_small_walltorch"))
6651                                         {
6652                                                 originhack[0] = 0;
6653                                                 originhack[1] = 0;
6654                                                 originhack[2] = 0;
6655                                                 overridecolor[0] = 1;
6656                                                 overridecolor[1] = 0.5;
6657                                                 overridecolor[2] = 0.1;
6658                                         }
6659                                 }
6660                         }
6661                         else if (!strcmp("style", key))
6662                                 style = atoi(value);
6663                         else if (!strcmp("skin", key))
6664                                 skin = (int)atof(value);
6665                         else if (!strcmp("pflags", key))
6666                                 pflags = (int)atof(value);
6667                         //else if (!strcmp("effects", key))
6668                         //      effects = (int)atof(value);
6669                         else if (cl.worldmodel->type == mod_brushq3)
6670                         {
6671                                 if (!strcmp("scale", key))
6672                                         lightscale = atof(value);
6673                                 if (!strcmp("fade", key))
6674                                         fadescale = atof(value);
6675                         }
6676                 }
6677                 if (!islight)
6678                         continue;
6679                 if (lightscale <= 0)
6680                         lightscale = 1;
6681                 if (fadescale <= 0)
6682                         fadescale = 1;
6683                 if (color[0] == color[1] && color[0] == color[2])
6684                 {
6685                         color[0] *= overridecolor[0];
6686                         color[1] *= overridecolor[1];
6687                         color[2] *= overridecolor[2];
6688                 }
6689                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6690                 color[0] = color[0] * light[0];
6691                 color[1] = color[1] * light[1];
6692                 color[2] = color[2] * light[2];
6693                 switch (type)
6694                 {
6695                 case LIGHTTYPE_MINUSX:
6696                         break;
6697                 case LIGHTTYPE_RECIPX:
6698                         radius *= 2;
6699                         VectorScale(color, (1.0f / 16.0f), color);
6700                         break;
6701                 case LIGHTTYPE_RECIPXX:
6702                         radius *= 2;
6703                         VectorScale(color, (1.0f / 16.0f), color);
6704                         break;
6705                 default:
6706                 case LIGHTTYPE_NONE:
6707                         break;
6708                 case LIGHTTYPE_SUN:
6709                         break;
6710                 case LIGHTTYPE_MINUSXX:
6711                         break;
6712                 }
6713                 VectorAdd(origin, originhack, origin);
6714                 if (radius >= 1)
6715                         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);
6716         }
6717         if (entfiledata)
6718                 Mem_Free(entfiledata);
6719 }
6720
6721
6722 static void R_Shadow_SetCursorLocationForView(void)
6723 {
6724         vec_t dist, push;
6725         vec3_t dest, endpos;
6726         trace_t trace;
6727         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6728         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6729         if (trace.fraction < 1)
6730         {
6731                 dist = trace.fraction * r_editlights_cursordistance.value;
6732                 push = r_editlights_cursorpushback.value;
6733                 if (push > dist)
6734                         push = dist;
6735                 push = -push;
6736                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6737                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6738         }
6739         else
6740         {
6741                 VectorClear( endpos );
6742         }
6743         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6744         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6745         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6746 }
6747
6748 void R_Shadow_UpdateWorldLightSelection(void)
6749 {
6750         if (r_editlights.integer)
6751         {
6752                 R_Shadow_SetCursorLocationForView();
6753                 R_Shadow_SelectLightInView();
6754         }
6755         else
6756                 R_Shadow_SelectLight(NULL);
6757 }
6758
6759 static void R_Shadow_EditLights_Clear_f(void)
6760 {
6761         R_Shadow_ClearWorldLights();
6762 }
6763
6764 void R_Shadow_EditLights_Reload_f(void)
6765 {
6766         if (!cl.worldmodel)
6767                 return;
6768         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6769         R_Shadow_ClearWorldLights();
6770         if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6771         {
6772                 R_Shadow_LoadWorldLights();
6773                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6774                         R_Shadow_LoadLightsFile();
6775         }
6776         if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6777         {
6778                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6779                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6780         }
6781 }
6782
6783 static void R_Shadow_EditLights_Save_f(void)
6784 {
6785         if (!cl.worldmodel)
6786                 return;
6787         R_Shadow_SaveWorldLights();
6788 }
6789
6790 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6791 {
6792         R_Shadow_ClearWorldLights();
6793         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6794 }
6795
6796 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6797 {
6798         R_Shadow_ClearWorldLights();
6799         R_Shadow_LoadLightsFile();
6800 }
6801
6802 static void R_Shadow_EditLights_Spawn_f(void)
6803 {
6804         vec3_t color;
6805         if (!r_editlights.integer)
6806         {
6807                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6808                 return;
6809         }
6810         if (Cmd_Argc() != 1)
6811         {
6812                 Con_Print("r_editlights_spawn does not take parameters\n");
6813                 return;
6814         }
6815         color[0] = color[1] = color[2] = 1;
6816         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6817 }
6818
6819 static void R_Shadow_EditLights_Edit_f(void)
6820 {
6821         vec3_t origin, angles, color;
6822         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6823         int style, shadows, flags, normalmode, realtimemode;
6824         char cubemapname[MAX_INPUTLINE];
6825         if (!r_editlights.integer)
6826         {
6827                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6828                 return;
6829         }
6830         if (!r_shadow_selectedlight)
6831         {
6832                 Con_Print("No selected light.\n");
6833                 return;
6834         }
6835         VectorCopy(r_shadow_selectedlight->origin, origin);
6836         VectorCopy(r_shadow_selectedlight->angles, angles);
6837         VectorCopy(r_shadow_selectedlight->color, color);
6838         radius = r_shadow_selectedlight->radius;
6839         style = r_shadow_selectedlight->style;
6840         if (r_shadow_selectedlight->cubemapname)
6841                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6842         else
6843                 cubemapname[0] = 0;
6844         shadows = r_shadow_selectedlight->shadow;
6845         corona = r_shadow_selectedlight->corona;
6846         coronasizescale = r_shadow_selectedlight->coronasizescale;
6847         ambientscale = r_shadow_selectedlight->ambientscale;
6848         diffusescale = r_shadow_selectedlight->diffusescale;
6849         specularscale = r_shadow_selectedlight->specularscale;
6850         flags = r_shadow_selectedlight->flags;
6851         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6852         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6853         if (!strcmp(Cmd_Argv(1), "origin"))
6854         {
6855                 if (Cmd_Argc() != 5)
6856                 {
6857                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6858                         return;
6859                 }
6860                 origin[0] = atof(Cmd_Argv(2));
6861                 origin[1] = atof(Cmd_Argv(3));
6862                 origin[2] = atof(Cmd_Argv(4));
6863         }
6864         else if (!strcmp(Cmd_Argv(1), "originscale"))
6865         {
6866                 if (Cmd_Argc() != 5)
6867                 {
6868                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6869                         return;
6870                 }
6871                 origin[0] *= atof(Cmd_Argv(2));
6872                 origin[1] *= atof(Cmd_Argv(3));
6873                 origin[2] *= atof(Cmd_Argv(4));
6874         }
6875         else if (!strcmp(Cmd_Argv(1), "originx"))
6876         {
6877                 if (Cmd_Argc() != 3)
6878                 {
6879                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6880                         return;
6881                 }
6882                 origin[0] = atof(Cmd_Argv(2));
6883         }
6884         else if (!strcmp(Cmd_Argv(1), "originy"))
6885         {
6886                 if (Cmd_Argc() != 3)
6887                 {
6888                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6889                         return;
6890                 }
6891                 origin[1] = atof(Cmd_Argv(2));
6892         }
6893         else if (!strcmp(Cmd_Argv(1), "originz"))
6894         {
6895                 if (Cmd_Argc() != 3)
6896                 {
6897                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6898                         return;
6899                 }
6900                 origin[2] = atof(Cmd_Argv(2));
6901         }
6902         else if (!strcmp(Cmd_Argv(1), "move"))
6903         {
6904                 if (Cmd_Argc() != 5)
6905                 {
6906                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6907                         return;
6908                 }
6909                 origin[0] += atof(Cmd_Argv(2));
6910                 origin[1] += atof(Cmd_Argv(3));
6911                 origin[2] += atof(Cmd_Argv(4));
6912         }
6913         else if (!strcmp(Cmd_Argv(1), "movex"))
6914         {
6915                 if (Cmd_Argc() != 3)
6916                 {
6917                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6918                         return;
6919                 }
6920                 origin[0] += atof(Cmd_Argv(2));
6921         }
6922         else if (!strcmp(Cmd_Argv(1), "movey"))
6923         {
6924                 if (Cmd_Argc() != 3)
6925                 {
6926                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6927                         return;
6928                 }
6929                 origin[1] += atof(Cmd_Argv(2));
6930         }
6931         else if (!strcmp(Cmd_Argv(1), "movez"))
6932         {
6933                 if (Cmd_Argc() != 3)
6934                 {
6935                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6936                         return;
6937                 }
6938                 origin[2] += atof(Cmd_Argv(2));
6939         }
6940         else if (!strcmp(Cmd_Argv(1), "angles"))
6941         {
6942                 if (Cmd_Argc() != 5)
6943                 {
6944                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6945                         return;
6946                 }
6947                 angles[0] = atof(Cmd_Argv(2));
6948                 angles[1] = atof(Cmd_Argv(3));
6949                 angles[2] = atof(Cmd_Argv(4));
6950         }
6951         else if (!strcmp(Cmd_Argv(1), "anglesx"))
6952         {
6953                 if (Cmd_Argc() != 3)
6954                 {
6955                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6956                         return;
6957                 }
6958                 angles[0] = atof(Cmd_Argv(2));
6959         }
6960         else if (!strcmp(Cmd_Argv(1), "anglesy"))
6961         {
6962                 if (Cmd_Argc() != 3)
6963                 {
6964                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6965                         return;
6966                 }
6967                 angles[1] = atof(Cmd_Argv(2));
6968         }
6969         else if (!strcmp(Cmd_Argv(1), "anglesz"))
6970         {
6971                 if (Cmd_Argc() != 3)
6972                 {
6973                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6974                         return;
6975                 }
6976                 angles[2] = atof(Cmd_Argv(2));
6977         }
6978         else if (!strcmp(Cmd_Argv(1), "color"))
6979         {
6980                 if (Cmd_Argc() != 5)
6981                 {
6982                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6983                         return;
6984                 }
6985                 color[0] = atof(Cmd_Argv(2));
6986                 color[1] = atof(Cmd_Argv(3));
6987                 color[2] = atof(Cmd_Argv(4));
6988         }
6989         else if (!strcmp(Cmd_Argv(1), "radius"))
6990         {
6991                 if (Cmd_Argc() != 3)
6992                 {
6993                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6994                         return;
6995                 }
6996                 radius = atof(Cmd_Argv(2));
6997         }
6998         else if (!strcmp(Cmd_Argv(1), "colorscale"))
6999         {
7000                 if (Cmd_Argc() == 3)
7001                 {
7002                         double scale = atof(Cmd_Argv(2));
7003                         color[0] *= scale;
7004                         color[1] *= scale;
7005                         color[2] *= scale;
7006                 }
7007                 else
7008                 {
7009                         if (Cmd_Argc() != 5)
7010                         {
7011                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
7012                                 return;
7013                         }
7014                         color[0] *= atof(Cmd_Argv(2));
7015                         color[1] *= atof(Cmd_Argv(3));
7016                         color[2] *= atof(Cmd_Argv(4));
7017                 }
7018         }
7019         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7020         {
7021                 if (Cmd_Argc() != 3)
7022                 {
7023                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7024                         return;
7025                 }
7026                 radius *= atof(Cmd_Argv(2));
7027         }
7028         else if (!strcmp(Cmd_Argv(1), "style"))
7029         {
7030                 if (Cmd_Argc() != 3)
7031                 {
7032                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7033                         return;
7034                 }
7035                 style = atoi(Cmd_Argv(2));
7036         }
7037         else if (!strcmp(Cmd_Argv(1), "cubemap"))
7038         {
7039                 if (Cmd_Argc() > 3)
7040                 {
7041                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7042                         return;
7043                 }
7044                 if (Cmd_Argc() == 3)
7045                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7046                 else
7047                         cubemapname[0] = 0;
7048         }
7049         else if (!strcmp(Cmd_Argv(1), "shadows"))
7050         {
7051                 if (Cmd_Argc() != 3)
7052                 {
7053                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7054                         return;
7055                 }
7056                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7057         }
7058         else if (!strcmp(Cmd_Argv(1), "corona"))
7059         {
7060                 if (Cmd_Argc() != 3)
7061                 {
7062                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7063                         return;
7064                 }
7065                 corona = atof(Cmd_Argv(2));
7066         }
7067         else if (!strcmp(Cmd_Argv(1), "coronasize"))
7068         {
7069                 if (Cmd_Argc() != 3)
7070                 {
7071                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7072                         return;
7073                 }
7074                 coronasizescale = atof(Cmd_Argv(2));
7075         }
7076         else if (!strcmp(Cmd_Argv(1), "ambient"))
7077         {
7078                 if (Cmd_Argc() != 3)
7079                 {
7080                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7081                         return;
7082                 }
7083                 ambientscale = atof(Cmd_Argv(2));
7084         }
7085         else if (!strcmp(Cmd_Argv(1), "diffuse"))
7086         {
7087                 if (Cmd_Argc() != 3)
7088                 {
7089                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7090                         return;
7091                 }
7092                 diffusescale = atof(Cmd_Argv(2));
7093         }
7094         else if (!strcmp(Cmd_Argv(1), "specular"))
7095         {
7096                 if (Cmd_Argc() != 3)
7097                 {
7098                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7099                         return;
7100                 }
7101                 specularscale = atof(Cmd_Argv(2));
7102         }
7103         else if (!strcmp(Cmd_Argv(1), "normalmode"))
7104         {
7105                 if (Cmd_Argc() != 3)
7106                 {
7107                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7108                         return;
7109                 }
7110                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7111         }
7112         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7113         {
7114                 if (Cmd_Argc() != 3)
7115                 {
7116                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7117                         return;
7118                 }
7119                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7120         }
7121         else
7122         {
7123                 Con_Print("usage: r_editlights_edit [property] [value]\n");
7124                 Con_Print("Selected light's properties:\n");
7125                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7126                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7127                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7128                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
7129                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
7130                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
7131                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7132                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
7133                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
7134                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
7135                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
7136                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
7137                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7138                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7139                 return;
7140         }
7141         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7142         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7143 }
7144
7145 static void R_Shadow_EditLights_EditAll_f(void)
7146 {
7147         size_t lightindex;
7148         dlight_t *light, *oldselected;
7149         size_t range;
7150
7151         if (!r_editlights.integer)
7152         {
7153                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7154                 return;
7155         }
7156
7157         oldselected = r_shadow_selectedlight;
7158         // EditLights doesn't seem to have a "remove" command or something so:
7159         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7160         for (lightindex = 0;lightindex < range;lightindex++)
7161         {
7162                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7163                 if (!light)
7164                         continue;
7165                 R_Shadow_SelectLight(light);
7166                 R_Shadow_EditLights_Edit_f();
7167         }
7168         // return to old selected (to not mess editing once selection is locked)
7169         R_Shadow_SelectLight(oldselected);
7170 }
7171
7172 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7173 {
7174         int lightnumber, lightcount;
7175         size_t lightindex, range;
7176         dlight_t *light;
7177         char temp[256];
7178         float x, y;
7179
7180         if (!r_editlights.integer)
7181                 return;
7182
7183         // update cvars so QC can query them
7184         if (r_shadow_selectedlight)
7185         {
7186                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7187                 Cvar_SetQuick(&r_editlights_current_origin, temp);
7188                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7189                 Cvar_SetQuick(&r_editlights_current_angles, temp);
7190                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7191                 Cvar_SetQuick(&r_editlights_current_color, temp);
7192                 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7193                 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7194                 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7195                 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7196                 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7197                 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7198                 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7199                 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7200                 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7201                 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7202                 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7203         }
7204
7205         // draw properties on screen
7206         if (!r_editlights_drawproperties.integer)
7207                 return;
7208         x = vid_conwidth.value - 320;
7209         y = 5;
7210         DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7211         lightnumber = -1;
7212         lightcount = 0;
7213         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7214         for (lightindex = 0;lightindex < range;lightindex++)
7215         {
7216                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7217                 if (!light)
7218                         continue;
7219                 if (light == r_shadow_selectedlight)
7220                         lightnumber = (int)lightindex;
7221                 lightcount++;
7222         }
7223         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;
7224         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;
7225         y += 8;
7226         if (r_shadow_selectedlight == NULL)
7227                 return;
7228         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;
7229         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;
7230         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;
7231         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;
7232         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;
7233         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;
7234         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;
7235         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;
7236         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;
7237         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;
7238         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;
7239         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;
7240         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;
7241         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;
7242         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;
7243         y += 8;
7244         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;
7245         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;
7246         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;
7247         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;
7248         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;
7249         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;
7250         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;
7251         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;
7252         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;
7253         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;
7254 }
7255
7256 static void R_Shadow_EditLights_ToggleShadow_f(void)
7257 {
7258         if (!r_editlights.integer)
7259         {
7260                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
7261                 return;
7262         }
7263         if (!r_shadow_selectedlight)
7264         {
7265                 Con_Print("No selected light.\n");
7266                 return;
7267         }
7268         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);
7269 }
7270
7271 static void R_Shadow_EditLights_ToggleCorona_f(void)
7272 {
7273         if (!r_editlights.integer)
7274         {
7275                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
7276                 return;
7277         }
7278         if (!r_shadow_selectedlight)
7279         {
7280                 Con_Print("No selected light.\n");
7281                 return;
7282         }
7283         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);
7284 }
7285
7286 static void R_Shadow_EditLights_Remove_f(void)
7287 {
7288         if (!r_editlights.integer)
7289         {
7290                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
7291                 return;
7292         }
7293         if (!r_shadow_selectedlight)
7294         {
7295                 Con_Print("No selected light.\n");
7296                 return;
7297         }
7298         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7299         r_shadow_selectedlight = NULL;
7300 }
7301
7302 static void R_Shadow_EditLights_Help_f(void)
7303 {
7304         Con_Print(
7305 "Documentation on r_editlights system:\n"
7306 "Settings:\n"
7307 "r_editlights : enable/disable editing mode\n"
7308 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7309 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7310 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7311 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7312 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7313 "Commands:\n"
7314 "r_editlights_help : this help\n"
7315 "r_editlights_clear : remove all lights\n"
7316 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7317 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7318 "r_editlights_save : save to .rtlights file\n"
7319 "r_editlights_spawn : create a light with default settings\n"
7320 "r_editlights_edit command : edit selected light - more documentation below\n"
7321 "r_editlights_remove : remove selected light\n"
7322 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7323 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7324 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7325 "Edit commands:\n"
7326 "origin x y z : set light location\n"
7327 "originx x: set x component of light location\n"
7328 "originy y: set y component of light location\n"
7329 "originz z: set z component of light location\n"
7330 "move x y z : adjust light location\n"
7331 "movex x: adjust x component of light location\n"
7332 "movey y: adjust y component of light location\n"
7333 "movez z: adjust z component of light location\n"
7334 "angles x y z : set light angles\n"
7335 "anglesx x: set x component of light angles\n"
7336 "anglesy y: set y component of light angles\n"
7337 "anglesz z: set z component of light angles\n"
7338 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7339 "radius radius : set radius (size) of light\n"
7340 "colorscale grey : multiply color of light (1 does nothing)\n"
7341 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7342 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7343 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7344 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7345 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7346 "cubemap basename : set filter cubemap of light\n"
7347 "shadows 1/0 : turn on/off shadows\n"
7348 "corona n : set corona intensity\n"
7349 "coronasize n : set corona size (0-1)\n"
7350 "ambient n : set ambient intensity (0-1)\n"
7351 "diffuse n : set diffuse intensity (0-1)\n"
7352 "specular n : set specular intensity (0-1)\n"
7353 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7354 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7355 "<nothing> : print light properties to console\n"
7356         );
7357 }
7358
7359 static void R_Shadow_EditLights_CopyInfo_f(void)
7360 {
7361         if (!r_editlights.integer)
7362         {
7363                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
7364                 return;
7365         }
7366         if (!r_shadow_selectedlight)
7367         {
7368                 Con_Print("No selected light.\n");
7369                 return;
7370         }
7371         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7372         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7373         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7374         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7375         if (r_shadow_selectedlight->cubemapname)
7376                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7377         else
7378                 r_shadow_bufferlight.cubemapname[0] = 0;
7379         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7380         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7381         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7382         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7383         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7384         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7385         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7386 }
7387
7388 static void R_Shadow_EditLights_PasteInfo_f(void)
7389 {
7390         if (!r_editlights.integer)
7391         {
7392                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
7393                 return;
7394         }
7395         if (!r_shadow_selectedlight)
7396         {
7397                 Con_Print("No selected light.\n");
7398                 return;
7399         }
7400         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);
7401 }
7402
7403 static void R_Shadow_EditLights_Lock_f(void)
7404 {
7405         if (!r_editlights.integer)
7406         {
7407                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
7408                 return;
7409         }
7410         if (r_editlights_lockcursor)
7411         {
7412                 r_editlights_lockcursor = false;
7413                 return;
7414         }
7415         if (!r_shadow_selectedlight)
7416         {
7417                 Con_Print("No selected light to lock on.\n");
7418                 return;
7419         }
7420         r_editlights_lockcursor = true;
7421 }
7422
7423 static void R_Shadow_EditLights_Init(void)
7424 {
7425         Cvar_RegisterVariable(&r_editlights);
7426         Cvar_RegisterVariable(&r_editlights_cursordistance);
7427         Cvar_RegisterVariable(&r_editlights_cursorpushback);
7428         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7429         Cvar_RegisterVariable(&r_editlights_cursorgrid);
7430         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7431         Cvar_RegisterVariable(&r_editlights_drawproperties);
7432         Cvar_RegisterVariable(&r_editlights_current_origin);
7433         Cvar_RegisterVariable(&r_editlights_current_angles);
7434         Cvar_RegisterVariable(&r_editlights_current_color);
7435         Cvar_RegisterVariable(&r_editlights_current_radius);
7436         Cvar_RegisterVariable(&r_editlights_current_corona);
7437         Cvar_RegisterVariable(&r_editlights_current_coronasize);
7438         Cvar_RegisterVariable(&r_editlights_current_style);
7439         Cvar_RegisterVariable(&r_editlights_current_shadows);
7440         Cvar_RegisterVariable(&r_editlights_current_cubemap);
7441         Cvar_RegisterVariable(&r_editlights_current_ambient);
7442         Cvar_RegisterVariable(&r_editlights_current_diffuse);
7443         Cvar_RegisterVariable(&r_editlights_current_specular);
7444         Cvar_RegisterVariable(&r_editlights_current_normalmode);
7445         Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7446         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7447         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7448         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)");
7449         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7450         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7451         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7452         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)");
7453         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7454         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7455         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7456         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7457         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7458         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7459         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)");
7460         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7461 }
7462
7463
7464
7465 /*
7466 =============================================================================
7467
7468 LIGHT SAMPLING
7469
7470 =============================================================================
7471 */
7472
7473 void R_LightPoint(float *color, const vec3_t p, const int flags)
7474 {
7475         int i, numlights, flag;
7476         float f, relativepoint[3], dist, dist2, lightradius2;
7477         vec3_t diffuse, n;
7478         rtlight_t *light;
7479         dlight_t *dlight;
7480
7481         if (r_fullbright.integer)
7482         {
7483                 VectorSet(color, 1, 1, 1);
7484                 return;
7485         }
7486
7487         VectorClear(color);
7488
7489         if (flags & LP_LIGHTMAP)
7490         {
7491                 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7492                 {
7493                         VectorClear(diffuse);
7494                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7495                         VectorAdd(color, diffuse, color);
7496                 }
7497                 else
7498                         VectorSet(color, 1, 1, 1);
7499                 color[0] += r_refdef.scene.ambient;
7500                 color[1] += r_refdef.scene.ambient;
7501                 color[2] += r_refdef.scene.ambient;
7502         }
7503
7504         if (flags & LP_RTWORLD)
7505         {
7506                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7507                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7508                 for (i = 0; i < numlights; i++)
7509                 {
7510                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7511                         if (!dlight)
7512                                 continue;
7513                         light = &dlight->rtlight;
7514                         if (!(light->flags & flag))
7515                                 continue;
7516                         // sample
7517                         lightradius2 = light->radius * light->radius;
7518                         VectorSubtract(light->shadoworigin, p, relativepoint);
7519                         dist2 = VectorLength2(relativepoint);
7520                         if (dist2 >= lightradius2)
7521                                 continue;
7522                         dist = sqrt(dist2) / light->radius;
7523                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7524                         if (f <= 0)
7525                                 continue;
7526                         // todo: add to both ambient and diffuse
7527                         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)
7528                                 VectorMA(color, f, light->currentcolor, color);
7529                 }
7530         }
7531         if (flags & LP_DYNLIGHT)
7532         {
7533                 // sample dlights
7534                 for (i = 0;i < r_refdef.scene.numlights;i++)
7535                 {
7536                         light = r_refdef.scene.lights[i];
7537                         // sample
7538                         lightradius2 = light->radius * light->radius;
7539                         VectorSubtract(light->shadoworigin, p, relativepoint);
7540                         dist2 = VectorLength2(relativepoint);
7541                         if (dist2 >= lightradius2)
7542                                 continue;
7543                         dist = sqrt(dist2) / light->radius;
7544                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7545                         if (f <= 0)
7546                                 continue;
7547                         // todo: add to both ambient and diffuse
7548                         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)
7549                                 VectorMA(color, f, light->color, color);
7550                 }
7551         }
7552 }
7553
7554 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7555 {
7556         int i, numlights, flag;
7557         rtlight_t *light;
7558         dlight_t *dlight;
7559         float relativepoint[3];
7560         float color[3];
7561         float dir[3];
7562         float dist;
7563         float dist2;
7564         float intensity;
7565         float sample[5*3];
7566         float lightradius2;
7567
7568         if (r_fullbright.integer)
7569         {
7570                 VectorSet(ambient, 1, 1, 1);
7571                 VectorClear(diffuse);
7572                 VectorClear(lightdir);
7573                 return;
7574         }
7575
7576         if (flags == LP_LIGHTMAP)
7577         {
7578                 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7579                 VectorClear(diffuse);
7580                 VectorClear(lightdir);
7581                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7582                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7583                 else
7584                         VectorSet(ambient, 1, 1, 1);
7585                 return;
7586         }
7587
7588         memset(sample, 0, sizeof(sample));
7589         VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7590
7591         if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7592         {
7593                 vec3_t tempambient;
7594                 VectorClear(tempambient);
7595                 VectorClear(color);
7596                 VectorClear(relativepoint);
7597                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7598                 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7599                 VectorScale(color, r_refdef.lightmapintensity, color);
7600                 VectorAdd(sample, tempambient, sample);
7601                 VectorMA(sample    , 0.5f            , color, sample    );
7602                 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7603                 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7604                 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7605                 // calculate a weighted average light direction as well
7606                 intensity = VectorLength(color);
7607                 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7608         }
7609
7610         if (flags & LP_RTWORLD)
7611         {
7612                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7613                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7614                 for (i = 0; i < numlights; i++)
7615                 {
7616                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7617                         if (!dlight)
7618                                 continue;
7619                         light = &dlight->rtlight;
7620                         if (!(light->flags & flag))
7621                                 continue;
7622                         // sample
7623                         lightradius2 = light->radius * light->radius;
7624                         VectorSubtract(light->shadoworigin, p, relativepoint);
7625                         dist2 = VectorLength2(relativepoint);
7626                         if (dist2 >= lightradius2)
7627                                 continue;
7628                         dist = sqrt(dist2) / light->radius;
7629                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7630                         if (intensity <= 0.0f)
7631                                 continue;
7632                         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)
7633                                 continue;
7634                         // scale down intensity to add to both ambient and diffuse
7635                         //intensity *= 0.5f;
7636                         VectorNormalize(relativepoint);
7637                         VectorScale(light->currentcolor, intensity, color);
7638                         VectorMA(sample    , 0.5f            , color, sample    );
7639                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7640                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7641                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7642                         // calculate a weighted average light direction as well
7643                         intensity *= VectorLength(color);
7644                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7645                 }
7646                 // FIXME: sample bouncegrid too!
7647         }
7648
7649         if (flags & LP_DYNLIGHT)
7650         {
7651                 // sample dlights
7652                 for (i = 0;i < r_refdef.scene.numlights;i++)
7653                 {
7654                         light = r_refdef.scene.lights[i];
7655                         // sample
7656                         lightradius2 = light->radius * light->radius;
7657                         VectorSubtract(light->shadoworigin, p, relativepoint);
7658                         dist2 = VectorLength2(relativepoint);
7659                         if (dist2 >= lightradius2)
7660                                 continue;
7661                         dist = sqrt(dist2) / light->radius;
7662                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7663                         if (intensity <= 0.0f)
7664                                 continue;
7665                         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)
7666                                 continue;
7667                         // scale down intensity to add to both ambient and diffuse
7668                         //intensity *= 0.5f;
7669                         VectorNormalize(relativepoint);
7670                         VectorScale(light->currentcolor, intensity, color);
7671                         VectorMA(sample    , 0.5f            , color, sample    );
7672                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7673                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7674                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7675                         // calculate a weighted average light direction as well
7676                         intensity *= VectorLength(color);
7677                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7678                 }
7679         }
7680
7681         // calculate the direction we'll use to reduce the sample to a directional light source
7682         VectorCopy(sample + 12, dir);
7683         //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7684         VectorNormalize(dir);
7685         // extract the diffuse color along the chosen direction and scale it
7686         diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7687         diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7688         diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7689         // subtract some of diffuse from ambient
7690         VectorMA(sample, -0.333f, diffuse, ambient);
7691         // store the normalized lightdir
7692         VectorCopy(dir, lightdir);
7693 }