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