]> git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
Cvar onChange for qc menu for stable branch
[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", "5", "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 float ambientcolor[3], const float diffusecolor[3], const float specularcolor[3])
3888 {
3889         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3890         R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, 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 float ambientcolor[3], const float diffusecolor[3])
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 *surfacepants = rsurface.texture->render_colormap_pants;
3990         const float *surfaceshirt = rsurface.texture->render_colormap_shirt;
3991         rtexture_t *basetexture = rsurface.texture->basetexture;
3992         rtexture_t *pantstexture = rsurface.texture->pantstexture;
3993         rtexture_t *shirttexture = rsurface.texture->shirttexture;
3994         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3995         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3996         VectorCopy(ambientcolor, ambientcolorbase);
3997         VectorCopy(diffusecolor, diffusecolorbase);
3998         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3999         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
4000         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
4001         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
4002         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (VectorLength2(diffusecolor) > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
4003         rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
4004         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4005         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
4006         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
4007         R_Mesh_TexBind(0, basetexture);
4008         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
4009         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
4010         switch(r_shadow_rendermode)
4011         {
4012         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4013                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
4014                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4015                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4016                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4017                 break;
4018         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4019                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
4020                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
4021                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
4022                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4023                 // fall through
4024         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4025                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
4026                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4027                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4028                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4029                 break;
4030         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4031                 break;
4032         default:
4033                 break;
4034         }
4035         //R_Mesh_TexBind(0, basetexture);
4036         R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4037         if (dopants)
4038         {
4039                 R_Mesh_TexBind(0, pantstexture);
4040                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4041         }
4042         if (doshirt)
4043         {
4044                 R_Mesh_TexBind(0, shirttexture);
4045                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4046         }
4047 }
4048
4049 extern cvar_t gl_lightmaps;
4050 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4051 {
4052         qboolean negated;
4053         float ambientcolor[3], diffusecolor[3], specularcolor[3];
4054         VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
4055         VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
4056         VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
4057         if (!r_shadow_usenormalmap.integer)
4058         {
4059                 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
4060                 VectorClear(diffusecolor);
4061                 VectorClear(specularcolor);
4062         }
4063         VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
4064         VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
4065         VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
4066         if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
4067                 return;
4068         negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0) && vid.support.ext_blend_subtract;
4069         if(negated)
4070         {
4071                 VectorNegate(ambientcolor, ambientcolor);
4072                 VectorNegate(diffusecolor, diffusecolor);
4073                 VectorNegate(specularcolor, specularcolor);
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, ambientcolor, diffusecolor, specularcolor);
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, ambientcolor, diffusecolor);
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_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
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_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_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
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_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_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_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
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_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_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.scene.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 = r_shadow_shadowmaptexturesize / 4;
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_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                         VectorNegate(ent->render_modellight_lightdir, tmp);
5841                         Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5842                 }
5843
5844                 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5845                 RSurf_ActiveModelEntity(ent, false, false, false);
5846                 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5847                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5848         }
5849
5850         // not really the right mode, but this will disable any silly stencil features
5851         R_Shadow_RenderMode_End();
5852
5853         // set up ortho view for rendering this pass
5854         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5855         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5856         //GL_ScissorTest(true);
5857         //R_EntityMatrix(&identitymatrix);
5858         //R_Mesh_ResetTextureState();
5859         R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5860
5861         // set up a darkening blend on shadowed areas
5862         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5863         //GL_DepthRange(0, 1);
5864         //GL_DepthTest(false);
5865         //GL_DepthMask(false);
5866         //GL_PolygonOffset(0, 0);CHECKGLERROR
5867         GL_Color(0, 0, 0, r_shadows_darken.value);
5868         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5869         //GL_DepthFunc(GL_ALWAYS);
5870         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5871
5872         // apply the blend to the shadowed areas
5873         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5874         R_SetupShader_Generic_NoTexture(false, true);
5875         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5876
5877         // restore the viewport
5878         R_SetViewport(&r_refdef.view.viewport);
5879
5880         // restore other state to normal
5881         //R_Shadow_RenderMode_End();
5882 }
5883
5884 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5885 {
5886         float zdist;
5887         vec3_t centerorigin;
5888 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5889         float vertex3f[12];
5890 #endif
5891         // if it's too close, skip it
5892         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5893                 return;
5894         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5895         if (zdist < 32)
5896                 return;
5897         if (usequery && r_numqueries + 2 <= r_maxqueries)
5898         {
5899                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5900                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5901                 // 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
5902                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5903
5904                 switch(vid.renderpath)
5905                 {
5906                 case RENDERPATH_GL11:
5907                 case RENDERPATH_GL13:
5908                 case RENDERPATH_GL20:
5909                 case RENDERPATH_GLES1:
5910                 case RENDERPATH_GLES2:
5911 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5912                         CHECKGLERROR
5913                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5914                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5915                         GL_DepthFunc(GL_ALWAYS);
5916                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5917                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5918                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5919                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5920                         GL_DepthFunc(GL_LEQUAL);
5921                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5922                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5923                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5924                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5925                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5926                         CHECKGLERROR
5927 #endif
5928                         break;
5929                 case RENDERPATH_D3D9:
5930                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5931                         break;
5932                 case RENDERPATH_D3D10:
5933                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5934                         break;
5935                 case RENDERPATH_D3D11:
5936                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5937                         break;
5938                 case RENDERPATH_SOFT:
5939                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5940                         break;
5941                 }
5942         }
5943         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5944 }
5945
5946 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5947
5948 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5949 {
5950         vec3_t color;
5951         unsigned int occlude = 0;
5952         GLint allpixels = 0, visiblepixels = 0;
5953
5954         // now we have to check the query result
5955         if (rtlight->corona_queryindex_visiblepixels)
5956         {
5957                 switch(vid.renderpath)
5958                 {
5959                 case RENDERPATH_GL20:
5960                 case RENDERPATH_GLES1:
5961                 case RENDERPATH_GLES2:
5962 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5963                         // See if we can use the GPU-side method to prevent implicit sync
5964                         if (vid.support.arb_query_buffer_object) {
5965 #define BUFFER_OFFSET(i)    ((GLint *)((unsigned char*)NULL + (i)))
5966                                 if (!r_shadow_occlusion_buf) {
5967                                         qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5968                                         qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5969                                         qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5970                                 } else {
5971                                         qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5972                                 }
5973                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5974                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5975                                 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5976                                 occlude = MATERIALFLAG_OCCLUDE;
5977                                 cscale *= rtlight->corona_visibility;
5978                                 CHECKGLERROR
5979                                 break;
5980                         }
5981                         // fallthrough
5982 #else
5983                         return;
5984 #endif
5985                 case RENDERPATH_GL11:
5986                 case RENDERPATH_GL13:
5987 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5988                         CHECKGLERROR
5989                         qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5990                         qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5991                         if (visiblepixels < 1 || allpixels < 1)
5992                                 return;
5993                         rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5994                         cscale *= rtlight->corona_visibility;
5995                         CHECKGLERROR
5996                         break;
5997 #else
5998                         return;
5999 #endif
6000                 case RENDERPATH_D3D9:
6001                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6002                         return;
6003                 case RENDERPATH_D3D10:
6004                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6005                         return;
6006                 case RENDERPATH_D3D11:
6007                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6008                         return;
6009                 case RENDERPATH_SOFT:
6010                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6011                         return;
6012                 default:
6013                         return;
6014                 }
6015         }
6016         else
6017         {
6018                 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
6019                         return;
6020         }
6021         VectorScale(rtlight->currentcolor, cscale, color);
6022         if (VectorLength(color) > (1.0f / 256.0f))
6023         {
6024                 float vertex3f[12];
6025                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6026                 if(negated)
6027                 {
6028                         VectorNegate(color, color);
6029                         GL_BlendEquationSubtract(true);
6030                 }
6031                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6032                 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);
6033                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6034                 if(negated)
6035                         GL_BlendEquationSubtract(false);
6036         }
6037 }
6038
6039 void R_Shadow_DrawCoronas(void)
6040 {
6041         int i, flag;
6042         qboolean usequery = false;
6043         size_t lightindex;
6044         dlight_t *light;
6045         rtlight_t *rtlight;
6046         size_t range;
6047         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6048                 return;
6049         if (r_fb.water.renderingscene)
6050                 return;
6051         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6052         R_EntityMatrix(&identitymatrix);
6053
6054         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6055
6056         // check occlusion of coronas
6057         // use GL_ARB_occlusion_query if available
6058         // otherwise use raytraces
6059         r_numqueries = 0;
6060         switch (vid.renderpath)
6061         {
6062         case RENDERPATH_GL11:
6063         case RENDERPATH_GL13:
6064         case RENDERPATH_GL20:
6065         case RENDERPATH_GLES1:
6066         case RENDERPATH_GLES2:
6067                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6068 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6069                 if (usequery)
6070                 {
6071                         GL_ColorMask(0,0,0,0);
6072                         if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6073                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6074                         {
6075                                 i = r_maxqueries;
6076                                 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6077                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6078                                 CHECKGLERROR
6079                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6080                                 CHECKGLERROR
6081                         }
6082                         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6083                         GL_BlendFunc(GL_ONE, GL_ZERO);
6084                         GL_CullFace(GL_NONE);
6085                         GL_DepthMask(false);
6086                         GL_DepthRange(0, 1);
6087                         GL_PolygonOffset(0, 0);
6088                         GL_DepthTest(true);
6089                         R_Mesh_ResetTextureState();
6090                         R_SetupShader_Generic_NoTexture(false, false);
6091                 }
6092 #endif
6093                 break;
6094         case RENDERPATH_D3D9:
6095                 usequery = false;
6096                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6097                 break;
6098         case RENDERPATH_D3D10:
6099                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6100                 break;
6101         case RENDERPATH_D3D11:
6102                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6103                 break;
6104         case RENDERPATH_SOFT:
6105                 usequery = false;
6106                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6107                 break;
6108         }
6109         for (lightindex = 0;lightindex < range;lightindex++)
6110         {
6111                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6112                 if (!light)
6113                         continue;
6114                 rtlight = &light->rtlight;
6115                 rtlight->corona_visibility = 0;
6116                 rtlight->corona_queryindex_visiblepixels = 0;
6117                 rtlight->corona_queryindex_allpixels = 0;
6118                 if (!(rtlight->flags & flag))
6119                         continue;
6120                 if (rtlight->corona <= 0)
6121                         continue;
6122                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6123                         continue;
6124                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6125         }
6126         for (i = 0;i < r_refdef.scene.numlights;i++)
6127         {
6128                 rtlight = r_refdef.scene.lights[i];
6129                 rtlight->corona_visibility = 0;
6130                 rtlight->corona_queryindex_visiblepixels = 0;
6131                 rtlight->corona_queryindex_allpixels = 0;
6132                 if (!(rtlight->flags & flag))
6133                         continue;
6134                 if (rtlight->corona <= 0)
6135                         continue;
6136                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6137         }
6138         if (usequery)
6139                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6140
6141         // now draw the coronas using the query data for intensity info
6142         for (lightindex = 0;lightindex < range;lightindex++)
6143         {
6144                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6145                 if (!light)
6146                         continue;
6147                 rtlight = &light->rtlight;
6148                 if (rtlight->corona_visibility <= 0)
6149                         continue;
6150                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6151         }
6152         for (i = 0;i < r_refdef.scene.numlights;i++)
6153         {
6154                 rtlight = r_refdef.scene.lights[i];
6155                 if (rtlight->corona_visibility <= 0)
6156                         continue;
6157                 if (gl_flashblend.integer)
6158                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6159                 else
6160                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6161         }
6162 }
6163
6164
6165
6166 static dlight_t *R_Shadow_NewWorldLight(void)
6167 {
6168         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6169 }
6170
6171 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)
6172 {
6173         matrix4x4_t matrix;
6174
6175         // 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
6176
6177         // validate parameters
6178         if (!cubemapname)
6179                 cubemapname = "";
6180
6181         // copy to light properties
6182         VectorCopy(origin, light->origin);
6183         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6184         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6185         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6186         /*
6187         light->color[0] = max(color[0], 0);
6188         light->color[1] = max(color[1], 0);
6189         light->color[2] = max(color[2], 0);
6190         */
6191         light->color[0] = color[0];
6192         light->color[1] = color[1];
6193         light->color[2] = color[2];
6194         light->radius = max(radius, 0);
6195         light->style = style;
6196         light->shadow = shadowenable;
6197         light->corona = corona;
6198         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6199         light->coronasizescale = coronasizescale;
6200         light->ambientscale = ambientscale;
6201         light->diffusescale = diffusescale;
6202         light->specularscale = specularscale;
6203         light->flags = flags;
6204
6205         // update renderable light data
6206         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6207         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);
6208 }
6209
6210 static void R_Shadow_FreeWorldLight(dlight_t *light)
6211 {
6212         if (r_shadow_selectedlight == light)
6213                 r_shadow_selectedlight = NULL;
6214         R_RTLight_Uncompile(&light->rtlight);
6215         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6216 }
6217
6218 void R_Shadow_ClearWorldLights(void)
6219 {
6220         size_t lightindex;
6221         dlight_t *light;
6222         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6223         for (lightindex = 0;lightindex < range;lightindex++)
6224         {
6225                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6226                 if (light)
6227                         R_Shadow_FreeWorldLight(light);
6228         }
6229         r_shadow_selectedlight = NULL;
6230 }
6231
6232 static void R_Shadow_SelectLight(dlight_t *light)
6233 {
6234         if (r_shadow_selectedlight)
6235                 r_shadow_selectedlight->selected = false;
6236         r_shadow_selectedlight = light;
6237         if (r_shadow_selectedlight)
6238                 r_shadow_selectedlight->selected = true;
6239 }
6240
6241 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6242 {
6243         // this is never batched (there can be only one)
6244         float vertex3f[12];
6245         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6246         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6247         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6248 }
6249
6250 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6251 {
6252         float intensity;
6253         float s;
6254         vec3_t spritecolor;
6255         skinframe_t *skinframe;
6256         float vertex3f[12];
6257
6258         // this is never batched (due to the ent parameter changing every time)
6259         // so numsurfaces == 1 and surfacelist[0] == lightnumber
6260         const dlight_t *light = (dlight_t *)ent;
6261         s = EDLIGHTSPRSIZE;
6262
6263         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6264
6265         intensity = 0.5f;
6266         VectorScale(light->color, intensity, spritecolor);
6267         if (VectorLength(spritecolor) < 0.1732f)
6268                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6269         if (VectorLength(spritecolor) > 1.0f)
6270                 VectorNormalize(spritecolor);
6271
6272         // draw light sprite
6273         if (light->cubemapname[0] && !light->shadow)
6274                 skinframe = r_editlights_sprcubemapnoshadowlight;
6275         else if (light->cubemapname[0])
6276                 skinframe = r_editlights_sprcubemaplight;
6277         else if (!light->shadow)
6278                 skinframe = r_editlights_sprnoshadowlight;
6279         else
6280                 skinframe = r_editlights_sprlight;
6281
6282         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);
6283         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6284
6285         // draw selection sprite if light is selected
6286         if (light->selected)
6287         {
6288                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6289                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6290                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6291         }
6292 }
6293
6294 void R_Shadow_DrawLightSprites(void)
6295 {
6296         size_t lightindex;
6297         dlight_t *light;
6298         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6299         for (lightindex = 0;lightindex < range;lightindex++)
6300         {
6301                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6302                 if (light)
6303                         R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6304         }
6305         if (!r_editlights_lockcursor)
6306                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6307 }
6308
6309 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6310 {
6311         unsigned int range;
6312         dlight_t *light;
6313         rtlight_t *rtlight;
6314         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6315         if (lightindex >= range)
6316                 return -1;
6317         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6318         if (!light)
6319                 return 0;
6320         rtlight = &light->rtlight;
6321         //if (!(rtlight->flags & flag))
6322         //      return 0;
6323         VectorCopy(rtlight->shadoworigin, origin);
6324         *radius = rtlight->radius;
6325         VectorCopy(rtlight->color, color);
6326         return 1;
6327 }
6328
6329 static void R_Shadow_SelectLightInView(void)
6330 {
6331         float bestrating, rating, temp[3];
6332         dlight_t *best;
6333         size_t lightindex;
6334         dlight_t *light;
6335         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6336         best = NULL;
6337         bestrating = 0;
6338
6339         if (r_editlights_lockcursor)
6340                 return;
6341         for (lightindex = 0;lightindex < range;lightindex++)
6342         {
6343                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6344                 if (!light)
6345                         continue;
6346                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6347                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6348                 if (rating >= 0.95)
6349                 {
6350                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6351                         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)
6352                         {
6353                                 bestrating = rating;
6354                                 best = light;
6355                         }
6356                 }
6357         }
6358         R_Shadow_SelectLight(best);
6359 }
6360
6361 void R_Shadow_LoadWorldLights(void)
6362 {
6363         int n, a, style, shadow, flags;
6364         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6365         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6366         if (cl.worldmodel == NULL)
6367         {
6368                 Con_Print("No map loaded.\n");
6369                 return;
6370         }
6371         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6372         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6373         if (lightsstring)
6374         {
6375                 s = lightsstring;
6376                 n = 0;
6377                 while (*s)
6378                 {
6379                         /*
6380                         t = s;
6381                         shadow = true;
6382                         for (;COM_Parse(t, true) && strcmp(
6383                         if (COM_Parse(t, true))
6384                         {
6385                                 if (com_token[0] == '!')
6386                                 {
6387                                         shadow = false;
6388                                         origin[0] = atof(com_token+1);
6389                                 }
6390                                 else
6391                                         origin[0] = atof(com_token);
6392                                 if (Com_Parse(t
6393                         }
6394                         */
6395                         t = s;
6396                         while (*s && *s != '\n' && *s != '\r')
6397                                 s++;
6398                         if (!*s)
6399                                 break;
6400                         tempchar = *s;
6401                         shadow = true;
6402                         // check for modifier flags
6403                         if (*t == '!')
6404                         {
6405                                 shadow = false;
6406                                 t++;
6407                         }
6408                         *s = 0;
6409 #if _MSC_VER >= 1400
6410 #define sscanf sscanf_s
6411 #endif
6412                         cubemapname[sizeof(cubemapname)-1] = 0;
6413 #if MAX_QPATH != 128
6414 #error update this code if MAX_QPATH changes
6415 #endif
6416                         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
6417 #if _MSC_VER >= 1400
6418 , sizeof(cubemapname)
6419 #endif
6420 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6421                         *s = tempchar;
6422                         if (a < 18)
6423                                 flags = LIGHTFLAG_REALTIMEMODE;
6424                         if (a < 17)
6425                                 specularscale = 1;
6426                         if (a < 16)
6427                                 diffusescale = 1;
6428                         if (a < 15)
6429                                 ambientscale = 0;
6430                         if (a < 14)
6431                                 coronasizescale = 0.25f;
6432                         if (a < 13)
6433                                 VectorClear(angles);
6434                         if (a < 10)
6435                                 corona = 0;
6436                         if (a < 9 || !strcmp(cubemapname, "\"\""))
6437                                 cubemapname[0] = 0;
6438                         // remove quotes on cubemapname
6439                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6440                         {
6441                                 size_t namelen;
6442                                 namelen = strlen(cubemapname) - 2;
6443                                 memmove(cubemapname, cubemapname + 1, namelen);
6444                                 cubemapname[namelen] = '\0';
6445                         }
6446                         if (a < 8)
6447                         {
6448                                 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);
6449                                 break;
6450                         }
6451                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6452                         if (*s == '\r')
6453                                 s++;
6454                         if (*s == '\n')
6455                                 s++;
6456                         n++;
6457                 }
6458                 if (*s)
6459                         Con_Printf("invalid rtlights file \"%s\"\n", name);
6460                 Mem_Free(lightsstring);
6461         }
6462 }
6463
6464 void R_Shadow_SaveWorldLights(void)
6465 {
6466         size_t lightindex;
6467         dlight_t *light;
6468         size_t bufchars, bufmaxchars;
6469         char *buf, *oldbuf;
6470         char name[MAX_QPATH];
6471         char line[MAX_INPUTLINE];
6472         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6473         // I hate lines which are 3 times my screen size :( --blub
6474         if (!range)
6475                 return;
6476         if (cl.worldmodel == NULL)
6477         {
6478                 Con_Print("No map loaded.\n");
6479                 return;
6480         }
6481         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6482         bufchars = bufmaxchars = 0;
6483         buf = NULL;
6484         for (lightindex = 0;lightindex < range;lightindex++)
6485         {
6486                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6487                 if (!light)
6488                         continue;
6489                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6490                         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);
6491                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6492                         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]);
6493                 else
6494                         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);
6495                 if (bufchars + strlen(line) > bufmaxchars)
6496                 {
6497                         bufmaxchars = bufchars + strlen(line) + 2048;
6498                         oldbuf = buf;
6499                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6500                         if (oldbuf)
6501                         {
6502                                 if (bufchars)
6503                                         memcpy(buf, oldbuf, bufchars);
6504                                 Mem_Free(oldbuf);
6505                         }
6506                 }
6507                 if (strlen(line))
6508                 {
6509                         memcpy(buf + bufchars, line, strlen(line));
6510                         bufchars += strlen(line);
6511                 }
6512         }
6513         if (bufchars)
6514                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6515         if (buf)
6516                 Mem_Free(buf);
6517 }
6518
6519 void R_Shadow_LoadLightsFile(void)
6520 {
6521         int n, a, style;
6522         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6523         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6524         if (cl.worldmodel == NULL)
6525         {
6526                 Con_Print("No map loaded.\n");
6527                 return;
6528         }
6529         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6530         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6531         if (lightsstring)
6532         {
6533                 s = lightsstring;
6534                 n = 0;
6535                 while (*s)
6536                 {
6537                         t = s;
6538                         while (*s && *s != '\n' && *s != '\r')
6539                                 s++;
6540                         if (!*s)
6541                                 break;
6542                         tempchar = *s;
6543                         *s = 0;
6544                         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);
6545                         *s = tempchar;
6546                         if (a < 14)
6547                         {
6548                                 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);
6549                                 break;
6550                         }
6551                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6552                         radius = bound(15, radius, 4096);
6553                         VectorScale(color, (2.0f / (8388608.0f)), color);
6554                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6555                         if (*s == '\r')
6556                                 s++;
6557                         if (*s == '\n')
6558                                 s++;
6559                         n++;
6560                 }
6561                 if (*s)
6562                         Con_Printf("invalid lights file \"%s\"\n", name);
6563                 Mem_Free(lightsstring);
6564         }
6565 }
6566
6567 // tyrlite/hmap2 light types in the delay field
6568 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6569
6570 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6571 {
6572         int entnum;
6573         int style;
6574         int islight;
6575         int skin;
6576         int pflags;
6577         //int effects;
6578         int type;
6579         int n;
6580         char *entfiledata;
6581         const char *data;
6582         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6583         char key[256], value[MAX_INPUTLINE];
6584         char vabuf[1024];
6585
6586         if (cl.worldmodel == NULL)
6587         {
6588                 Con_Print("No map loaded.\n");
6589                 return;
6590         }
6591         // try to load a .ent file first
6592         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6593         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6594         // and if that is not found, fall back to the bsp file entity string
6595         if (!data)
6596                 data = cl.worldmodel->brush.entities;
6597         if (!data)
6598                 return;
6599         for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6600         {
6601                 type = LIGHTTYPE_MINUSX;
6602                 origin[0] = origin[1] = origin[2] = 0;
6603                 originhack[0] = originhack[1] = originhack[2] = 0;
6604                 angles[0] = angles[1] = angles[2] = 0;
6605                 color[0] = color[1] = color[2] = 1;
6606                 light[0] = light[1] = light[2] = 1;light[3] = 300;
6607                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6608                 fadescale = 1;
6609                 lightscale = 1;
6610                 style = 0;
6611                 skin = 0;
6612                 pflags = 0;
6613                 //effects = 0;
6614                 islight = false;
6615                 while (1)
6616                 {
6617                         if (!COM_ParseToken_Simple(&data, false, false, true))
6618                                 break; // error
6619                         if (com_token[0] == '}')
6620                                 break; // end of entity
6621                         if (com_token[0] == '_')
6622                                 strlcpy(key, com_token + 1, sizeof(key));
6623                         else
6624                                 strlcpy(key, com_token, sizeof(key));
6625                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
6626                                 key[strlen(key)-1] = 0;
6627                         if (!COM_ParseToken_Simple(&data, false, false, true))
6628                                 break; // error
6629                         strlcpy(value, com_token, sizeof(value));
6630
6631                         // now that we have the key pair worked out...
6632                         if (!strcmp("light", key))
6633                         {
6634                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6635                                 if (n == 1)
6636                                 {
6637                                         // quake
6638                                         light[0] = vec[0] * (1.0f / 256.0f);
6639                                         light[1] = vec[0] * (1.0f / 256.0f);
6640                                         light[2] = vec[0] * (1.0f / 256.0f);
6641                                         light[3] = vec[0];
6642                                 }
6643                                 else if (n == 4)
6644                                 {
6645                                         // halflife
6646                                         light[0] = vec[0] * (1.0f / 255.0f);
6647                                         light[1] = vec[1] * (1.0f / 255.0f);
6648                                         light[2] = vec[2] * (1.0f / 255.0f);
6649                                         light[3] = vec[3];
6650                                 }
6651                         }
6652                         else if (!strcmp("delay", key))
6653                                 type = atoi(value);
6654                         else if (!strcmp("origin", key))
6655                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6656                         else if (!strcmp("angle", key))
6657                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6658                         else if (!strcmp("angles", key))
6659                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6660                         else if (!strcmp("color", key))
6661                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6662                         else if (!strcmp("wait", key))
6663                                 fadescale = atof(value);
6664                         else if (!strcmp("classname", key))
6665                         {
6666                                 if (!strncmp(value, "light", 5))
6667                                 {
6668                                         islight = true;
6669                                         if (!strcmp(value, "light_fluoro"))
6670                                         {
6671                                                 originhack[0] = 0;
6672                                                 originhack[1] = 0;
6673                                                 originhack[2] = 0;
6674                                                 overridecolor[0] = 1;
6675                                                 overridecolor[1] = 1;
6676                                                 overridecolor[2] = 1;
6677                                         }
6678                                         if (!strcmp(value, "light_fluorospark"))
6679                                         {
6680                                                 originhack[0] = 0;
6681                                                 originhack[1] = 0;
6682                                                 originhack[2] = 0;
6683                                                 overridecolor[0] = 1;
6684                                                 overridecolor[1] = 1;
6685                                                 overridecolor[2] = 1;
6686                                         }
6687                                         if (!strcmp(value, "light_globe"))
6688                                         {
6689                                                 originhack[0] = 0;
6690                                                 originhack[1] = 0;
6691                                                 originhack[2] = 0;
6692                                                 overridecolor[0] = 1;
6693                                                 overridecolor[1] = 0.8;
6694                                                 overridecolor[2] = 0.4;
6695                                         }
6696                                         if (!strcmp(value, "light_flame_large_yellow"))
6697                                         {
6698                                                 originhack[0] = 0;
6699                                                 originhack[1] = 0;
6700                                                 originhack[2] = 0;
6701                                                 overridecolor[0] = 1;
6702                                                 overridecolor[1] = 0.5;
6703                                                 overridecolor[2] = 0.1;
6704                                         }
6705                                         if (!strcmp(value, "light_flame_small_yellow"))
6706                                         {
6707                                                 originhack[0] = 0;
6708                                                 originhack[1] = 0;
6709                                                 originhack[2] = 0;
6710                                                 overridecolor[0] = 1;
6711                                                 overridecolor[1] = 0.5;
6712                                                 overridecolor[2] = 0.1;
6713                                         }
6714                                         if (!strcmp(value, "light_torch_small_white"))
6715                                         {
6716                                                 originhack[0] = 0;
6717                                                 originhack[1] = 0;
6718                                                 originhack[2] = 0;
6719                                                 overridecolor[0] = 1;
6720                                                 overridecolor[1] = 0.5;
6721                                                 overridecolor[2] = 0.1;
6722                                         }
6723                                         if (!strcmp(value, "light_torch_small_walltorch"))
6724                                         {
6725                                                 originhack[0] = 0;
6726                                                 originhack[1] = 0;
6727                                                 originhack[2] = 0;
6728                                                 overridecolor[0] = 1;
6729                                                 overridecolor[1] = 0.5;
6730                                                 overridecolor[2] = 0.1;
6731                                         }
6732                                 }
6733                         }
6734                         else if (!strcmp("style", key))
6735                                 style = atoi(value);
6736                         else if (!strcmp("skin", key))
6737                                 skin = (int)atof(value);
6738                         else if (!strcmp("pflags", key))
6739                                 pflags = (int)atof(value);
6740                         //else if (!strcmp("effects", key))
6741                         //      effects = (int)atof(value);
6742                         else if (cl.worldmodel->type == mod_brushq3)
6743                         {
6744                                 if (!strcmp("scale", key))
6745                                         lightscale = atof(value);
6746                                 if (!strcmp("fade", key))
6747                                         fadescale = atof(value);
6748                         }
6749                 }
6750                 if (!islight)
6751                         continue;
6752                 if (lightscale <= 0)
6753                         lightscale = 1;
6754                 if (fadescale <= 0)
6755                         fadescale = 1;
6756                 if (color[0] == color[1] && color[0] == color[2])
6757                 {
6758                         color[0] *= overridecolor[0];
6759                         color[1] *= overridecolor[1];
6760                         color[2] *= overridecolor[2];
6761                 }
6762                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6763                 color[0] = color[0] * light[0];
6764                 color[1] = color[1] * light[1];
6765                 color[2] = color[2] * light[2];
6766                 switch (type)
6767                 {
6768                 case LIGHTTYPE_MINUSX:
6769                         break;
6770                 case LIGHTTYPE_RECIPX:
6771                         radius *= 2;
6772                         VectorScale(color, (1.0f / 16.0f), color);
6773                         break;
6774                 case LIGHTTYPE_RECIPXX:
6775                         radius *= 2;
6776                         VectorScale(color, (1.0f / 16.0f), color);
6777                         break;
6778                 default:
6779                 case LIGHTTYPE_NONE:
6780                         break;
6781                 case LIGHTTYPE_SUN:
6782                         break;
6783                 case LIGHTTYPE_MINUSXX:
6784                         break;
6785                 }
6786                 VectorAdd(origin, originhack, origin);
6787                 if (radius >= 1)
6788                         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);
6789         }
6790         if (entfiledata)
6791                 Mem_Free(entfiledata);
6792 }
6793
6794
6795 static void R_Shadow_SetCursorLocationForView(void)
6796 {
6797         vec_t dist, push;
6798         vec3_t dest, endpos;
6799         trace_t trace;
6800         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6801         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
6802         if (trace.fraction < 1)
6803         {
6804                 dist = trace.fraction * r_editlights_cursordistance.value;
6805                 push = r_editlights_cursorpushback.value;
6806                 if (push > dist)
6807                         push = dist;
6808                 push = -push;
6809                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6810                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6811         }
6812         else
6813         {
6814                 VectorClear( endpos );
6815         }
6816         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6817         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6818         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6819 }
6820
6821 void R_Shadow_UpdateWorldLightSelection(void)
6822 {
6823         if (r_editlights.integer)
6824         {
6825                 R_Shadow_SetCursorLocationForView();
6826                 R_Shadow_SelectLightInView();
6827         }
6828         else
6829                 R_Shadow_SelectLight(NULL);
6830 }
6831
6832 static void R_Shadow_EditLights_Clear_f(void)
6833 {
6834         R_Shadow_ClearWorldLights();
6835 }
6836
6837 void R_Shadow_EditLights_Reload_f(void)
6838 {
6839         if (!cl.worldmodel)
6840                 return;
6841         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6842         R_Shadow_ClearWorldLights();
6843         if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6844         {
6845                 R_Shadow_LoadWorldLights();
6846                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6847                         R_Shadow_LoadLightsFile();
6848         }
6849         if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6850         {
6851                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6852                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6853         }
6854 }
6855
6856 static void R_Shadow_EditLights_Save_f(void)
6857 {
6858         if (!cl.worldmodel)
6859                 return;
6860         R_Shadow_SaveWorldLights();
6861 }
6862
6863 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6864 {
6865         R_Shadow_ClearWorldLights();
6866         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6867 }
6868
6869 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6870 {
6871         R_Shadow_ClearWorldLights();
6872         R_Shadow_LoadLightsFile();
6873 }
6874
6875 static void R_Shadow_EditLights_Spawn_f(void)
6876 {
6877         vec3_t color;
6878         if (!r_editlights.integer)
6879         {
6880                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6881                 return;
6882         }
6883         if (Cmd_Argc() != 1)
6884         {
6885                 Con_Print("r_editlights_spawn does not take parameters\n");
6886                 return;
6887         }
6888         color[0] = color[1] = color[2] = 1;
6889         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6890 }
6891
6892 static void R_Shadow_EditLights_Edit_f(void)
6893 {
6894         vec3_t origin, angles, color;
6895         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6896         int style, shadows, flags, normalmode, realtimemode;
6897         char cubemapname[MAX_INPUTLINE];
6898         if (!r_editlights.integer)
6899         {
6900                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6901                 return;
6902         }
6903         if (!r_shadow_selectedlight)
6904         {
6905                 Con_Print("No selected light.\n");
6906                 return;
6907         }
6908         VectorCopy(r_shadow_selectedlight->origin, origin);
6909         VectorCopy(r_shadow_selectedlight->angles, angles);
6910         VectorCopy(r_shadow_selectedlight->color, color);
6911         radius = r_shadow_selectedlight->radius;
6912         style = r_shadow_selectedlight->style;
6913         if (r_shadow_selectedlight->cubemapname)
6914                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6915         else
6916                 cubemapname[0] = 0;
6917         shadows = r_shadow_selectedlight->shadow;
6918         corona = r_shadow_selectedlight->corona;
6919         coronasizescale = r_shadow_selectedlight->coronasizescale;
6920         ambientscale = r_shadow_selectedlight->ambientscale;
6921         diffusescale = r_shadow_selectedlight->diffusescale;
6922         specularscale = r_shadow_selectedlight->specularscale;
6923         flags = r_shadow_selectedlight->flags;
6924         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6925         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6926         if (!strcmp(Cmd_Argv(1), "origin"))
6927         {
6928                 if (Cmd_Argc() != 5)
6929                 {
6930                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6931                         return;
6932                 }
6933                 origin[0] = atof(Cmd_Argv(2));
6934                 origin[1] = atof(Cmd_Argv(3));
6935                 origin[2] = atof(Cmd_Argv(4));
6936         }
6937         else if (!strcmp(Cmd_Argv(1), "originscale"))
6938         {
6939                 if (Cmd_Argc() != 5)
6940                 {
6941                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6942                         return;
6943                 }
6944                 origin[0] *= atof(Cmd_Argv(2));
6945                 origin[1] *= atof(Cmd_Argv(3));
6946                 origin[2] *= atof(Cmd_Argv(4));
6947         }
6948         else if (!strcmp(Cmd_Argv(1), "originx"))
6949         {
6950                 if (Cmd_Argc() != 3)
6951                 {
6952                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6953                         return;
6954                 }
6955                 origin[0] = atof(Cmd_Argv(2));
6956         }
6957         else if (!strcmp(Cmd_Argv(1), "originy"))
6958         {
6959                 if (Cmd_Argc() != 3)
6960                 {
6961                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6962                         return;
6963                 }
6964                 origin[1] = atof(Cmd_Argv(2));
6965         }
6966         else if (!strcmp(Cmd_Argv(1), "originz"))
6967         {
6968                 if (Cmd_Argc() != 3)
6969                 {
6970                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6971                         return;
6972                 }
6973                 origin[2] = atof(Cmd_Argv(2));
6974         }
6975         else if (!strcmp(Cmd_Argv(1), "move"))
6976         {
6977                 if (Cmd_Argc() != 5)
6978                 {
6979                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6980                         return;
6981                 }
6982                 origin[0] += atof(Cmd_Argv(2));
6983                 origin[1] += atof(Cmd_Argv(3));
6984                 origin[2] += atof(Cmd_Argv(4));
6985         }
6986         else if (!strcmp(Cmd_Argv(1), "movex"))
6987         {
6988                 if (Cmd_Argc() != 3)
6989                 {
6990                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6991                         return;
6992                 }
6993                 origin[0] += atof(Cmd_Argv(2));
6994         }
6995         else if (!strcmp(Cmd_Argv(1), "movey"))
6996         {
6997                 if (Cmd_Argc() != 3)
6998                 {
6999                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7000                         return;
7001                 }
7002                 origin[1] += atof(Cmd_Argv(2));
7003         }
7004         else if (!strcmp(Cmd_Argv(1), "movez"))
7005         {
7006                 if (Cmd_Argc() != 3)
7007                 {
7008                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7009                         return;
7010                 }
7011                 origin[2] += atof(Cmd_Argv(2));
7012         }
7013         else if (!strcmp(Cmd_Argv(1), "angles"))
7014         {
7015                 if (Cmd_Argc() != 5)
7016                 {
7017                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7018                         return;
7019                 }
7020                 angles[0] = atof(Cmd_Argv(2));
7021                 angles[1] = atof(Cmd_Argv(3));
7022                 angles[2] = atof(Cmd_Argv(4));
7023         }
7024         else if (!strcmp(Cmd_Argv(1), "anglesx"))
7025         {
7026                 if (Cmd_Argc() != 3)
7027                 {
7028                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7029                         return;
7030                 }
7031                 angles[0] = atof(Cmd_Argv(2));
7032         }
7033         else if (!strcmp(Cmd_Argv(1), "anglesy"))
7034         {
7035                 if (Cmd_Argc() != 3)
7036                 {
7037                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7038                         return;
7039                 }
7040                 angles[1] = atof(Cmd_Argv(2));
7041         }
7042         else if (!strcmp(Cmd_Argv(1), "anglesz"))
7043         {
7044                 if (Cmd_Argc() != 3)
7045                 {
7046                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7047                         return;
7048                 }
7049                 angles[2] = atof(Cmd_Argv(2));
7050         }
7051         else if (!strcmp(Cmd_Argv(1), "color"))
7052         {
7053                 if (Cmd_Argc() != 5)
7054                 {
7055                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7056                         return;
7057                 }
7058                 color[0] = atof(Cmd_Argv(2));
7059                 color[1] = atof(Cmd_Argv(3));
7060                 color[2] = atof(Cmd_Argv(4));
7061         }
7062         else if (!strcmp(Cmd_Argv(1), "radius"))
7063         {
7064                 if (Cmd_Argc() != 3)
7065                 {
7066                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7067                         return;
7068                 }
7069                 radius = atof(Cmd_Argv(2));
7070         }
7071         else if (!strcmp(Cmd_Argv(1), "colorscale"))
7072         {
7073                 if (Cmd_Argc() == 3)
7074                 {
7075                         double scale = atof(Cmd_Argv(2));
7076                         color[0] *= scale;
7077                         color[1] *= scale;
7078                         color[2] *= scale;
7079                 }
7080                 else
7081                 {
7082                         if (Cmd_Argc() != 5)
7083                         {
7084                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
7085                                 return;
7086                         }
7087                         color[0] *= atof(Cmd_Argv(2));
7088                         color[1] *= atof(Cmd_Argv(3));
7089                         color[2] *= atof(Cmd_Argv(4));
7090                 }
7091         }
7092         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7093         {
7094                 if (Cmd_Argc() != 3)
7095                 {
7096                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7097                         return;
7098                 }
7099                 radius *= atof(Cmd_Argv(2));
7100         }
7101         else if (!strcmp(Cmd_Argv(1), "style"))
7102         {
7103                 if (Cmd_Argc() != 3)
7104                 {
7105                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7106                         return;
7107                 }
7108                 style = atoi(Cmd_Argv(2));
7109         }
7110         else if (!strcmp(Cmd_Argv(1), "cubemap"))
7111         {
7112                 if (Cmd_Argc() > 3)
7113                 {
7114                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7115                         return;
7116                 }
7117                 if (Cmd_Argc() == 3)
7118                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7119                 else
7120                         cubemapname[0] = 0;
7121         }
7122         else if (!strcmp(Cmd_Argv(1), "shadows"))
7123         {
7124                 if (Cmd_Argc() != 3)
7125                 {
7126                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7127                         return;
7128                 }
7129                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7130         }
7131         else if (!strcmp(Cmd_Argv(1), "corona"))
7132         {
7133                 if (Cmd_Argc() != 3)
7134                 {
7135                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7136                         return;
7137                 }
7138                 corona = atof(Cmd_Argv(2));
7139         }
7140         else if (!strcmp(Cmd_Argv(1), "coronasize"))
7141         {
7142                 if (Cmd_Argc() != 3)
7143                 {
7144                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7145                         return;
7146                 }
7147                 coronasizescale = atof(Cmd_Argv(2));
7148         }
7149         else if (!strcmp(Cmd_Argv(1), "ambient"))
7150         {
7151                 if (Cmd_Argc() != 3)
7152                 {
7153                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7154                         return;
7155                 }
7156                 ambientscale = atof(Cmd_Argv(2));
7157         }
7158         else if (!strcmp(Cmd_Argv(1), "diffuse"))
7159         {
7160                 if (Cmd_Argc() != 3)
7161                 {
7162                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7163                         return;
7164                 }
7165                 diffusescale = atof(Cmd_Argv(2));
7166         }
7167         else if (!strcmp(Cmd_Argv(1), "specular"))
7168         {
7169                 if (Cmd_Argc() != 3)
7170                 {
7171                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7172                         return;
7173                 }
7174                 specularscale = atof(Cmd_Argv(2));
7175         }
7176         else if (!strcmp(Cmd_Argv(1), "normalmode"))
7177         {
7178                 if (Cmd_Argc() != 3)
7179                 {
7180                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7181                         return;
7182                 }
7183                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7184         }
7185         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7186         {
7187                 if (Cmd_Argc() != 3)
7188                 {
7189                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7190                         return;
7191                 }
7192                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7193         }
7194         else
7195         {
7196                 Con_Print("usage: r_editlights_edit [property] [value]\n");
7197                 Con_Print("Selected light's properties:\n");
7198                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7199                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7200                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7201                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
7202                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
7203                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
7204                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7205                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
7206                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
7207                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
7208                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
7209                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
7210                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7211                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7212                 return;
7213         }
7214         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7215         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7216 }
7217
7218 static void R_Shadow_EditLights_EditAll_f(void)
7219 {
7220         size_t lightindex;
7221         dlight_t *light, *oldselected;
7222         size_t range;
7223
7224         if (!r_editlights.integer)
7225         {
7226                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7227                 return;
7228         }
7229
7230         oldselected = r_shadow_selectedlight;
7231         // EditLights doesn't seem to have a "remove" command or something so:
7232         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7233         for (lightindex = 0;lightindex < range;lightindex++)
7234         {
7235                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7236                 if (!light)
7237                         continue;
7238                 R_Shadow_SelectLight(light);
7239                 R_Shadow_EditLights_Edit_f();
7240         }
7241         // return to old selected (to not mess editing once selection is locked)
7242         R_Shadow_SelectLight(oldselected);
7243 }
7244
7245 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7246 {
7247         int lightnumber, lightcount;
7248         size_t lightindex, range;
7249         dlight_t *light;
7250         char temp[256];
7251         float x, y;
7252
7253         if (!r_editlights.integer)
7254                 return;
7255
7256         // update cvars so QC can query them
7257         if (r_shadow_selectedlight)
7258         {
7259                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7260                 Cvar_SetQuick(&r_editlights_current_origin, temp);
7261                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7262                 Cvar_SetQuick(&r_editlights_current_angles, temp);
7263                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7264                 Cvar_SetQuick(&r_editlights_current_color, temp);
7265                 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7266                 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7267                 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7268                 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7269                 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7270                 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7271                 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7272                 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7273                 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7274                 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7275                 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7276         }
7277
7278         // draw properties on screen
7279         if (!r_editlights_drawproperties.integer)
7280                 return;
7281         x = vid_conwidth.value - 320;
7282         y = 5;
7283         DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7284         lightnumber = -1;
7285         lightcount = 0;
7286         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7287         for (lightindex = 0;lightindex < range;lightindex++)
7288         {
7289                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7290                 if (!light)
7291                         continue;
7292                 if (light == r_shadow_selectedlight)
7293                         lightnumber = (int)lightindex;
7294                 lightcount++;
7295         }
7296         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;
7297         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;
7298         y += 8;
7299         if (r_shadow_selectedlight == NULL)
7300                 return;
7301         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;
7302         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;
7303         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;
7304         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;
7305         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;
7306         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;
7307         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;
7308         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;
7309         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;
7310         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;
7311         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;
7312         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;
7313         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;
7314         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;
7315         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;
7316         y += 8;
7317         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;
7318         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;
7319         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;
7320         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;
7321         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;
7322         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;
7323         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;
7324         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;
7325         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;
7326         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;
7327 }
7328
7329 static void R_Shadow_EditLights_ToggleShadow_f(void)
7330 {
7331         if (!r_editlights.integer)
7332         {
7333                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
7334                 return;
7335         }
7336         if (!r_shadow_selectedlight)
7337         {
7338                 Con_Print("No selected light.\n");
7339                 return;
7340         }
7341         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);
7342 }
7343
7344 static void R_Shadow_EditLights_ToggleCorona_f(void)
7345 {
7346         if (!r_editlights.integer)
7347         {
7348                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
7349                 return;
7350         }
7351         if (!r_shadow_selectedlight)
7352         {
7353                 Con_Print("No selected light.\n");
7354                 return;
7355         }
7356         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);
7357 }
7358
7359 static void R_Shadow_EditLights_Remove_f(void)
7360 {
7361         if (!r_editlights.integer)
7362         {
7363                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
7364                 return;
7365         }
7366         if (!r_shadow_selectedlight)
7367         {
7368                 Con_Print("No selected light.\n");
7369                 return;
7370         }
7371         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7372         r_shadow_selectedlight = NULL;
7373 }
7374
7375 static void R_Shadow_EditLights_Help_f(void)
7376 {
7377         Con_Print(
7378 "Documentation on r_editlights system:\n"
7379 "Settings:\n"
7380 "r_editlights : enable/disable editing mode\n"
7381 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7382 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7383 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7384 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7385 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7386 "Commands:\n"
7387 "r_editlights_help : this help\n"
7388 "r_editlights_clear : remove all lights\n"
7389 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7390 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7391 "r_editlights_save : save to .rtlights file\n"
7392 "r_editlights_spawn : create a light with default settings\n"
7393 "r_editlights_edit command : edit selected light - more documentation below\n"
7394 "r_editlights_remove : remove selected light\n"
7395 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7396 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7397 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7398 "Edit commands:\n"
7399 "origin x y z : set light location\n"
7400 "originx x: set x component of light location\n"
7401 "originy y: set y component of light location\n"
7402 "originz z: set z component of light location\n"
7403 "move x y z : adjust light location\n"
7404 "movex x: adjust x component of light location\n"
7405 "movey y: adjust y component of light location\n"
7406 "movez z: adjust z component of light location\n"
7407 "angles x y z : set light angles\n"
7408 "anglesx x: set x component of light angles\n"
7409 "anglesy y: set y component of light angles\n"
7410 "anglesz z: set z component of light angles\n"
7411 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7412 "radius radius : set radius (size) of light\n"
7413 "colorscale grey : multiply color of light (1 does nothing)\n"
7414 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7415 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7416 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7417 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7418 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7419 "cubemap basename : set filter cubemap of light\n"
7420 "shadows 1/0 : turn on/off shadows\n"
7421 "corona n : set corona intensity\n"
7422 "coronasize n : set corona size (0-1)\n"
7423 "ambient n : set ambient intensity (0-1)\n"
7424 "diffuse n : set diffuse intensity (0-1)\n"
7425 "specular n : set specular intensity (0-1)\n"
7426 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7427 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7428 "<nothing> : print light properties to console\n"
7429         );
7430 }
7431
7432 static void R_Shadow_EditLights_CopyInfo_f(void)
7433 {
7434         if (!r_editlights.integer)
7435         {
7436                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
7437                 return;
7438         }
7439         if (!r_shadow_selectedlight)
7440         {
7441                 Con_Print("No selected light.\n");
7442                 return;
7443         }
7444         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7445         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7446         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7447         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7448         if (r_shadow_selectedlight->cubemapname)
7449                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7450         else
7451                 r_shadow_bufferlight.cubemapname[0] = 0;
7452         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7453         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7454         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7455         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7456         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7457         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7458         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7459 }
7460
7461 static void R_Shadow_EditLights_PasteInfo_f(void)
7462 {
7463         if (!r_editlights.integer)
7464         {
7465                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
7466                 return;
7467         }
7468         if (!r_shadow_selectedlight)
7469         {
7470                 Con_Print("No selected light.\n");
7471                 return;
7472         }
7473         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);
7474 }
7475
7476 static void R_Shadow_EditLights_Lock_f(void)
7477 {
7478         if (!r_editlights.integer)
7479         {
7480                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
7481                 return;
7482         }
7483         if (r_editlights_lockcursor)
7484         {
7485                 r_editlights_lockcursor = false;
7486                 return;
7487         }
7488         if (!r_shadow_selectedlight)
7489         {
7490                 Con_Print("No selected light to lock on.\n");
7491                 return;
7492         }
7493         r_editlights_lockcursor = true;
7494 }
7495
7496 static void R_Shadow_EditLights_Init(void)
7497 {
7498         Cvar_RegisterVariable(&r_editlights);
7499         Cvar_RegisterVariable(&r_editlights_cursordistance);
7500         Cvar_RegisterVariable(&r_editlights_cursorpushback);
7501         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7502         Cvar_RegisterVariable(&r_editlights_cursorgrid);
7503         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7504         Cvar_RegisterVariable(&r_editlights_drawproperties);
7505         Cvar_RegisterVariable(&r_editlights_current_origin);
7506         Cvar_RegisterVariable(&r_editlights_current_angles);
7507         Cvar_RegisterVariable(&r_editlights_current_color);
7508         Cvar_RegisterVariable(&r_editlights_current_radius);
7509         Cvar_RegisterVariable(&r_editlights_current_corona);
7510         Cvar_RegisterVariable(&r_editlights_current_coronasize);
7511         Cvar_RegisterVariable(&r_editlights_current_style);
7512         Cvar_RegisterVariable(&r_editlights_current_shadows);
7513         Cvar_RegisterVariable(&r_editlights_current_cubemap);
7514         Cvar_RegisterVariable(&r_editlights_current_ambient);
7515         Cvar_RegisterVariable(&r_editlights_current_diffuse);
7516         Cvar_RegisterVariable(&r_editlights_current_specular);
7517         Cvar_RegisterVariable(&r_editlights_current_normalmode);
7518         Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7519         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7520         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7521         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)");
7522         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7523         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7524         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7525         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)");
7526         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7527         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7528         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7529         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7530         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7531         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7532         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)");
7533         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7534 }
7535
7536
7537
7538 /*
7539 =============================================================================
7540
7541 LIGHT SAMPLING
7542
7543 =============================================================================
7544 */
7545
7546 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
7547 {
7548         int i, numlights, flag, q;
7549         rtlight_t *light;
7550         dlight_t *dlight;
7551         float relativepoint[3];
7552         float color[3];
7553         float dist;
7554         float dist2;
7555         float intensity;
7556         float sa[3], sx[3], sy[3], sz[3], sd[3];
7557         float lightradius2;
7558
7559         // use first order spherical harmonics to combine directional lights
7560         for (q = 0; q < 3; q++)
7561                 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
7562
7563         if (flags & LP_LIGHTMAP)
7564         {
7565                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7566                 {
7567                         float tempambient[3];
7568                         for (q = 0; q < 3; q++)
7569                                 tempambient[q] = color[q] = relativepoint[q] = 0;
7570                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7571                         // calculate a weighted average light direction as well
7572                         intensity = VectorLength(color);
7573                         for (q = 0; q < 3; q++)
7574                         {
7575                                 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
7576                                 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
7577                                 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
7578                                 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
7579                                 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
7580                         }
7581                 }
7582                 else
7583                 {
7584                         // unlit map - fullbright but scaled by lightmapintensity
7585                         for (q = 0; q < 3; q++)
7586                                 sa[q] += lightmapintensity;
7587                 }
7588         }
7589
7590         if (flags & LP_RTWORLD)
7591         {
7592                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7593                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7594                 for (i = 0; i < numlights; i++)
7595                 {
7596                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7597                         if (!dlight)
7598                                 continue;
7599                         light = &dlight->rtlight;
7600                         if (!(light->flags & flag))
7601                                 continue;
7602                         // sample
7603                         lightradius2 = light->radius * light->radius;
7604                         VectorSubtract(light->shadoworigin, p, relativepoint);
7605                         dist2 = VectorLength2(relativepoint);
7606                         if (dist2 >= lightradius2)
7607                                 continue;
7608                         dist = sqrt(dist2) / light->radius;
7609                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7610                         if (intensity <= 0.0f)
7611                                 continue;
7612                         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)
7613                                 continue;
7614                         for (q = 0; q < 3; q++)
7615                                 color[q] = light->currentcolor[q] * intensity;
7616                         intensity = VectorLength(color);
7617                         VectorNormalize(relativepoint);
7618                         for (q = 0; q < 3; q++)
7619                         {
7620                                 sa[q] += 0.5f * color[q];
7621                                 sx[q] += relativepoint[0] * color[q];
7622                                 sy[q] += relativepoint[1] * color[q];
7623                                 sz[q] += relativepoint[2] * color[q];
7624                                 sd[q] += intensity * relativepoint[q];
7625                         }
7626                 }
7627                 // FIXME: sample bouncegrid too!
7628         }
7629
7630         if (flags & LP_DYNLIGHT)
7631         {
7632                 // sample dlights
7633                 for (i = 0;i < r_refdef.scene.numlights;i++)
7634                 {
7635                         light = r_refdef.scene.lights[i];
7636                         // sample
7637                         lightradius2 = light->radius * light->radius;
7638                         VectorSubtract(light->shadoworigin, p, relativepoint);
7639                         dist2 = VectorLength2(relativepoint);
7640                         if (dist2 >= lightradius2)
7641                                 continue;
7642                         dist = sqrt(dist2) / light->radius;
7643                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7644                         if (intensity <= 0.0f)
7645                                 continue;
7646                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7647                                 continue;
7648                         for (q = 0; q < 3; q++)
7649                                 color[q] = light->currentcolor[q] * intensity;
7650                         intensity = VectorLength(color);
7651                         VectorNormalize(relativepoint);
7652                         for (q = 0; q < 3; q++)
7653                         {
7654                                 sa[q] += 0.5f * color[q];
7655                                 sx[q] += relativepoint[0] * color[q];
7656                                 sy[q] += relativepoint[1] * color[q];
7657                                 sz[q] += relativepoint[2] * color[q];
7658                                 sd[q] += intensity * relativepoint[q];
7659                         }
7660                 }
7661         }
7662
7663         // calculate the weighted-average light direction (bentnormal)
7664         for (q = 0; q < 3; q++)
7665                 lightdir[q] = sd[q];
7666         VectorNormalize(lightdir);
7667         for (q = 0; q < 3; q++)
7668         {
7669                 // extract the diffuse color along the chosen direction and scale it
7670                 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
7671                 // subtract some of diffuse from ambient
7672                 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;
7673         }
7674 }