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