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