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