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