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