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