]> git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
bouncegrid now uses high precision 48bpp accumulation array while also
[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
2518                                 VectorScale(shotcolor, r_shadow_bouncegrid_particlebounceintensity.value, shotcolor);
2519                                 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2520                                         VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2521                                 if (VectorLength2(shotcolor) < 3.0f)
2522                                         break;
2523                                 r_refdef.stats.bouncegrid_bounces++;
2524                                 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2525                                 {
2526                                         // random direction, primarily along plane normal
2527                                         s = VectorDistance(cliptrace.endpos, clipend);
2528                                         if (r_shadow_bouncegrid_stablerandom.integer < 0)
2529                                                 VectorRandom(clipend);
2530                                         else
2531                                                 VectorCheeseRandom(clipend);
2532                                         VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2533                                         VectorNormalize(clipend);
2534                                         VectorScale(clipend, s, clipend);
2535                                 }
2536                                 else
2537                                 {
2538                                         // reflect the remaining portion of the line across plane normal
2539                                         VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2540                                         VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2541                                 }
2542                                 // calculate the new line start and end
2543                                 VectorCopy(cliptrace.endpos, clipstart);
2544                                 VectorAdd(clipstart, clipend, clipend);
2545                         }
2546                 }
2547         }
2548         if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2549                 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2550         else
2551         {
2552                 VectorCopy(resolution, r_shadow_bouncegridresolution);
2553                 if (r_shadow_bouncegridtexture)
2554                         R_FreeTexture(r_shadow_bouncegridtexture);
2555                 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);
2556         }
2557         r_shadow_bouncegridtime = realtime;
2558 }
2559
2560 #define MAXPARTICLESPERLIGHT 262144
2561 #define MAXLIGHTSPERDRAW 1024
2562
2563 static void R_Shadow_RenderParticlesForLight(rtlight_t *rtlight)
2564 {
2565         int batchcount;
2566         int i;
2567         int j;
2568         int bouncecount;
2569         int hitsupercontentsmask;
2570         int n;
2571         int shotparticles;
2572         int shootparticles = 0;
2573         int bouncelimit;
2574         int maxbounce;
2575         unsigned int seed = 0;
2576         static unsigned short bouncelight_elements[MAXLIGHTSPERDRAW*36];
2577         static float vertex3f[MAXLIGHTSPERDRAW*24];
2578         static float lightorigin4f[MAXLIGHTSPERDRAW*32];
2579         static float color4f[MAXLIGHTSPERDRAW*32];
2580         float scaledpoints[8][3];
2581         float *v3f;
2582         float *lo4f;
2583         float *c4f;
2584         rtlight_particle_t *p;
2585         vec_t wantparticles = 0;
2586         vec_t s;
2587         vec_t radius;
2588         vec_t particlesize;
2589         vec_t iparticlesize;
2590 //      vec3_t offset;
2591 //      vec3_t right;
2592 //      vec3_t up;
2593         vec4_t org;
2594         vec4_t color;
2595         vec3_t currentcolor;
2596         vec3_t clipstart;
2597         vec3_t clipend;
2598         vec3_t shotcolor;
2599         trace_t cliptrace;
2600         if (!rtlight->draw || !rtlight->isstatic || !r_shadow_usingdeferredprepass)
2601                 return;
2602         if (r_shadow_particletrace.integer)
2603         {
2604                 radius = rtlight->radius * bound(0.0001f, r_shadow_particletrace_radiusscale.value, 1.0f) - r_shadow_particletrace_size.value;
2605                 s = rtlight->radius / bound(1.0f, r_shadow_particletrace_particlespacing.value * r_shadow_particletrace_size.value, 1048576.0f);
2606                 wantparticles = s*s;
2607                 n = (int)bound(0, wantparticles, MAXPARTICLESPERLIGHT);
2608         }
2609         else
2610                 n = 0;
2611         shootparticles = (int)(n * r_shadow_particletrace_updatepercentage.value);
2612         if ((n && !rtlight->particlecache_particles) || rtlight->particlecache_maxparticles != n)
2613         {
2614                 if (rtlight->particlecache_particles)
2615                         Mem_Free(rtlight->particlecache_particles);
2616                 rtlight->particlecache_particles = NULL;
2617                 rtlight->particlecache_numparticles = 0;
2618                 rtlight->particlecache_maxparticles = n;
2619                 rtlight->particlecache_updateparticle = 0;
2620                 if (rtlight->particlecache_maxparticles)
2621                         rtlight->particlecache_particles = (rtlight_particle_t *)Mem_Alloc(r_main_mempool, rtlight->particlecache_maxparticles * sizeof(*rtlight->particlecache_particles));
2622                 shootparticles = n * 16;
2623         }
2624
2625         if (!rtlight->particlecache_maxparticles)
2626                 return;
2627
2628 //      if (rtlight->particlecache_numparticles < rtlight->particlecache_maxparticles)
2629 //              shootparticles = rtlight->particlecache_maxparticles;
2630
2631 //      if (rtlight->particlecache_numparticles >= rtlight->particlecache_maxparticles)
2632 //              shootparticles = 0;
2633
2634         maxbounce = bound(1, r_shadow_particletrace_maxbounce.integer, 16);
2635         //r_refdef.stats.lights_bouncelightsupdated += shootparticles;
2636         for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2637         {
2638                 seed = rtlight->particlecache_updateparticle;
2639                 VectorSet(shotcolor, 1.0f, 1.0f, 1.0f);
2640                 VectorCopy(rtlight->shadoworigin, clipstart);
2641                 VectorRandom(clipend);
2642                 VectorMA(clipstart, radius, clipend, clipend);
2643                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2644                 bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2645                 for (bouncecount = 0;;bouncecount++)
2646                 {
2647                         cliptrace = CL_TraceLine(clipstart, clipend, MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2648                         //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2649                         if (cliptrace.fraction >= 1.0f)
2650                                 break;
2651                         if (VectorLength2(shotcolor) < (1.0f / 262144.0f))
2652                                 break;
2653                         if (bouncecount >= bouncelimit)
2654                         {
2655                                 VectorCopy(cliptrace.endpos, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].origin);
2656                                 VectorCopy(shotcolor, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].color);
2657                                 rtlight->particlecache_updateparticle++;
2658                                 if (rtlight->particlecache_numparticles < rtlight->particlecache_updateparticle)
2659                                         rtlight->particlecache_numparticles = rtlight->particlecache_updateparticle;
2660                                 if (rtlight->particlecache_updateparticle >= rtlight->particlecache_maxparticles)
2661                                 {
2662                                         rtlight->particlecache_updateparticle = 0;
2663                                         shotparticles = shootparticles;
2664                                 }
2665                                 break;
2666                         }
2667                         // scale down shot color by bounce intensity and texture color
2668                         VectorScale(shotcolor, r_shadow_particletrace_bounceintensity.value, shotcolor);
2669                         if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2670                                 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2671                         // reflect the remaining portion of the line across plane normal
2672                         //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2673                         //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2674                         // random direction, primarily along plane normal
2675                         s = VectorDistance(cliptrace.endpos, clipend);
2676                         VectorRandom(clipend);
2677                         VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2678                         VectorNormalize(clipend);
2679                         VectorScale(clipend, s, clipend);
2680                         // calculate the new line start and end
2681                         VectorCopy(cliptrace.endpos, clipstart);
2682                         VectorAdd(clipstart, clipend, clipend);
2683                 }
2684         }
2685
2686         if (!rtlight->particlecache_numparticles)
2687                 return;
2688
2689         // render the particles as deferred lights
2690 // do global setup needed for the chosen lighting mode
2691         R_Shadow_RenderMode_Reset();
2692         r_shadow_rendermode = r_shadow_lightingrendermode;
2693         r_shadow_usingshadowmap2d = false;
2694         R_EntityMatrix(&identitymatrix);
2695         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2696         // only draw light where this geometry was already rendered AND the
2697         // stencil is 128 (values other than this mean shadow)
2698         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2699         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2700         R_SetupShader_DeferredBounceLight();
2701         GL_ColorMask(1,1,1,1);
2702         GL_DepthMask(false);
2703         GL_DepthRange(0, 1);
2704         GL_PolygonOffset(0, 0);
2705         GL_DepthTest(true);
2706         GL_DepthFunc(GL_GREATER);
2707         GL_CullFace(r_refdef.view.cullface_back);
2708         s = r_shadow_particletrace_intensity.value / (float)rtlight->particlecache_numparticles;
2709         VectorScale(rtlight->currentcolor, s, currentcolor);
2710         particlesize = bound(0.0001f, r_shadow_particletrace_size.value, 1024.0f);
2711         iparticlesize = 1.0f / particlesize;
2712 //      VectorScale(r_refdef.view.forward, particlesize, offset);
2713 //      VectorScale(r_refdef.view.left, -particlesize, right);
2714 //      VectorScale(r_refdef.view.up, particlesize, up);
2715         org[3] = iparticlesize;
2716         color[3] = 1.0f;
2717         v3f = vertex3f;
2718         lo4f = lightorigin4f;
2719         c4f = color4f;
2720         batchcount = 0;
2721         if (!bouncelight_elements[1])
2722                 for (i = 0;i < MAXLIGHTSPERDRAW;i++)
2723                         for (j = 0;j < 36;j++)
2724                                 bouncelight_elements[i*36+j] = i*8+bboxelements[j];
2725         for (j = 0;j < 8;j++)
2726                 VectorScale(bboxpoints[j], particlesize, scaledpoints[j]);
2727         //r_refdef.stats.lights_bouncelightscounted += rtlight->particlecache_numparticles;
2728         for (j = 0, p = rtlight->particlecache_particles, n = rtlight->particlecache_numparticles;j < n;j++, p++)
2729         {
2730                 VectorCopy(p->origin, org);
2731                 // org[3] is set above
2732                 VectorMultiply(p->color, currentcolor, color);
2733                 // color[3] is set above
2734                 VectorAdd(scaledpoints[0], org, v3f +  0);
2735                 VectorAdd(scaledpoints[1], org, v3f +  3);
2736                 VectorAdd(scaledpoints[2], org, v3f +  6);
2737                 VectorAdd(scaledpoints[3], org, v3f +  9);
2738                 VectorAdd(scaledpoints[4], org, v3f + 12);
2739                 VectorAdd(scaledpoints[5], org, v3f + 15);
2740                 VectorAdd(scaledpoints[6], org, v3f + 18);
2741                 VectorAdd(scaledpoints[7], org, v3f + 21);
2742                 Vector4Copy(org, lo4f +  0);
2743                 Vector4Copy(org, lo4f +  4);
2744                 Vector4Copy(org, lo4f +  8);
2745                 Vector4Copy(org, lo4f + 12);
2746                 Vector4Copy(org, lo4f + 16);
2747                 Vector4Copy(org, lo4f + 20);
2748                 Vector4Copy(org, lo4f + 24);
2749                 Vector4Copy(org, lo4f + 28);
2750                 Vector4Copy(color, c4f + 0);
2751                 Vector4Copy(color, c4f + 4);
2752                 Vector4Copy(color, c4f + 8);
2753                 Vector4Copy(color, c4f + 12);
2754                 Vector4Copy(color, c4f + 16);
2755                 Vector4Copy(color, c4f + 20);
2756                 Vector4Copy(color, c4f + 24);
2757                 Vector4Copy(color, c4f + 28);
2758                 v3f += 24;
2759                 lo4f += 32;
2760                 c4f += 32;
2761                 batchcount++;
2762                 if (batchcount >= MAXLIGHTSPERDRAW)
2763                 {
2764                         //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2765                         R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2766                         R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2767                         v3f = vertex3f;
2768                         lo4f = lightorigin4f;
2769                         c4f = color4f;
2770                         batchcount = 0;
2771                 }
2772         }
2773         if (batchcount)
2774         {
2775                 //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2776                 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2777                 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2778                 v3f = vertex3f;
2779                 lo4f = lightorigin4f;
2780                 c4f = color4f;
2781                 batchcount = 0;
2782         }
2783 }
2784
2785 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2786 {
2787         R_Shadow_RenderMode_Reset();
2788         GL_BlendFunc(GL_ONE, GL_ONE);
2789         GL_DepthRange(0, 1);
2790         GL_DepthTest(r_showshadowvolumes.integer < 2);
2791         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2792         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2793         GL_CullFace(GL_NONE);
2794         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2795 }
2796
2797 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2798 {
2799         R_Shadow_RenderMode_Reset();
2800         GL_BlendFunc(GL_ONE, GL_ONE);
2801         GL_DepthRange(0, 1);
2802         GL_DepthTest(r_showlighting.integer < 2);
2803         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2804         if (!transparent)
2805                 GL_DepthFunc(GL_EQUAL);
2806         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2807         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2808 }
2809
2810 void R_Shadow_RenderMode_End(void)
2811 {
2812         R_Shadow_RenderMode_Reset();
2813         R_Shadow_RenderMode_ActiveLight(NULL);
2814         GL_DepthMask(true);
2815         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2816         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2817 }
2818
2819 int bboxedges[12][2] =
2820 {
2821         // top
2822         {0, 1}, // +X
2823         {0, 2}, // +Y
2824         {1, 3}, // Y, +X
2825         {2, 3}, // X, +Y
2826         // bottom
2827         {4, 5}, // +X
2828         {4, 6}, // +Y
2829         {5, 7}, // Y, +X
2830         {6, 7}, // X, +Y
2831         // verticals
2832         {0, 4}, // +Z
2833         {1, 5}, // X, +Z
2834         {2, 6}, // Y, +Z
2835         {3, 7}, // XY, +Z
2836 };
2837
2838 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2839 {
2840         if (!r_shadow_scissor.integer)
2841         {
2842                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2843                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2844                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2845                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2846                 return false;
2847         }
2848         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2849                 return true; // invisible
2850         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2851         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2852         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2853         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2854                 r_refdef.stats.lights_scissored++;
2855         return false;
2856 }
2857
2858 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2859 {
2860         int i;
2861         const float *vertex3f;
2862         const float *normal3f;
2863         float *color4f;
2864         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2865         switch (r_shadow_rendermode)
2866         {
2867         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2868         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2869                 if (VectorLength2(diffusecolor) > 0)
2870                 {
2871                         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)
2872                         {
2873                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2874                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2875                                 if ((dot = DotProduct(n, v)) < 0)
2876                                 {
2877                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2878                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2879                                 }
2880                                 else
2881                                         VectorCopy(ambientcolor, color4f);
2882                                 if (r_refdef.fogenabled)
2883                                 {
2884                                         float f;
2885                                         f = RSurf_FogVertex(vertex3f);
2886                                         VectorScale(color4f, f, color4f);
2887                                 }
2888                                 color4f[3] = 1;
2889                         }
2890                 }
2891                 else
2892                 {
2893                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2894                         {
2895                                 VectorCopy(ambientcolor, color4f);
2896                                 if (r_refdef.fogenabled)
2897                                 {
2898                                         float f;
2899                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2900                                         f = RSurf_FogVertex(vertex3f);
2901                                         VectorScale(color4f + 4*i, f, color4f);
2902                                 }
2903                                 color4f[3] = 1;
2904                         }
2905                 }
2906                 break;
2907         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2908                 if (VectorLength2(diffusecolor) > 0)
2909                 {
2910                         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)
2911                         {
2912                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2913                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2914                                 {
2915                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2916                                         if ((dot = DotProduct(n, v)) < 0)
2917                                         {
2918                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2919                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2920                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2921                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2922                                         }
2923                                         else
2924                                         {
2925                                                 color4f[0] = ambientcolor[0] * distintensity;
2926                                                 color4f[1] = ambientcolor[1] * distintensity;
2927                                                 color4f[2] = ambientcolor[2] * distintensity;
2928                                         }
2929                                         if (r_refdef.fogenabled)
2930                                         {
2931                                                 float f;
2932                                                 f = RSurf_FogVertex(vertex3f);
2933                                                 VectorScale(color4f, f, color4f);
2934                                         }
2935                                 }
2936                                 else
2937                                         VectorClear(color4f);
2938                                 color4f[3] = 1;
2939                         }
2940                 }
2941                 else
2942                 {
2943                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2944                         {
2945                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2946                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2947                                 {
2948                                         color4f[0] = ambientcolor[0] * distintensity;
2949                                         color4f[1] = ambientcolor[1] * distintensity;
2950                                         color4f[2] = ambientcolor[2] * distintensity;
2951                                         if (r_refdef.fogenabled)
2952                                         {
2953                                                 float f;
2954                                                 f = RSurf_FogVertex(vertex3f);
2955                                                 VectorScale(color4f, f, color4f);
2956                                         }
2957                                 }
2958                                 else
2959                                         VectorClear(color4f);
2960                                 color4f[3] = 1;
2961                         }
2962                 }
2963                 break;
2964         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2965                 if (VectorLength2(diffusecolor) > 0)
2966                 {
2967                         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)
2968                         {
2969                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2970                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2971                                 {
2972                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2973                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2974                                         if ((dot = DotProduct(n, v)) < 0)
2975                                         {
2976                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2977                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2978                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2979                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2980                                         }
2981                                         else
2982                                         {
2983                                                 color4f[0] = ambientcolor[0] * distintensity;
2984                                                 color4f[1] = ambientcolor[1] * distintensity;
2985                                                 color4f[2] = ambientcolor[2] * distintensity;
2986                                         }
2987                                         if (r_refdef.fogenabled)
2988                                         {
2989                                                 float f;
2990                                                 f = RSurf_FogVertex(vertex3f);
2991                                                 VectorScale(color4f, f, color4f);
2992                                         }
2993                                 }
2994                                 else
2995                                         VectorClear(color4f);
2996                                 color4f[3] = 1;
2997                         }
2998                 }
2999                 else
3000                 {
3001                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3002                         {
3003                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3004                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3005                                 {
3006                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3007                                         color4f[0] = ambientcolor[0] * distintensity;
3008                                         color4f[1] = ambientcolor[1] * distintensity;
3009                                         color4f[2] = ambientcolor[2] * distintensity;
3010                                         if (r_refdef.fogenabled)
3011                                         {
3012                                                 float f;
3013                                                 f = RSurf_FogVertex(vertex3f);
3014                                                 VectorScale(color4f, f, color4f);
3015                                         }
3016                                 }
3017                                 else
3018                                         VectorClear(color4f);
3019                                 color4f[3] = 1;
3020                         }
3021                 }
3022                 break;
3023         default:
3024                 break;
3025         }
3026 }
3027
3028 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3029 {
3030         // used to display how many times a surface is lit for level design purposes
3031         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3032         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3033         RSurf_DrawBatch();
3034 }
3035
3036 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3037 {
3038         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3039         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
3040         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3041                 GL_DepthFunc(GL_EQUAL);
3042         RSurf_DrawBatch();
3043         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3044                 GL_DepthFunc(GL_LEQUAL);
3045 }
3046
3047 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3048 {
3049         int renders;
3050         int i;
3051         int stop;
3052         int newfirstvertex;
3053         int newlastvertex;
3054         int newnumtriangles;
3055         int *newe;
3056         const int *e;
3057         float *c;
3058         int maxtriangles = 4096;
3059         static int newelements[4096*3];
3060         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3061         for (renders = 0;renders < 4;renders++)
3062         {
3063                 stop = true;
3064                 newfirstvertex = 0;
3065                 newlastvertex = 0;
3066                 newnumtriangles = 0;
3067                 newe = newelements;
3068                 // due to low fillrate on the cards this vertex lighting path is
3069                 // designed for, we manually cull all triangles that do not
3070                 // contain a lit vertex
3071                 // this builds batches of triangles from multiple surfaces and
3072                 // renders them at once
3073                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3074                 {
3075                         if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3076                         {
3077                                 if (newnumtriangles)
3078                                 {
3079                                         newfirstvertex = min(newfirstvertex, e[0]);
3080                                         newlastvertex  = max(newlastvertex, e[0]);
3081                                 }
3082                                 else
3083                                 {
3084                                         newfirstvertex = e[0];
3085                                         newlastvertex = e[0];
3086                                 }
3087                                 newfirstvertex = min(newfirstvertex, e[1]);
3088                                 newlastvertex  = max(newlastvertex, e[1]);
3089                                 newfirstvertex = min(newfirstvertex, e[2]);
3090                                 newlastvertex  = max(newlastvertex, e[2]);
3091                                 newe[0] = e[0];
3092                                 newe[1] = e[1];
3093                                 newe[2] = e[2];
3094                                 newnumtriangles++;
3095                                 newe += 3;
3096                                 if (newnumtriangles >= maxtriangles)
3097                                 {
3098                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3099                                         newnumtriangles = 0;
3100                                         newe = newelements;
3101                                         stop = false;
3102                                 }
3103                         }
3104                 }
3105                 if (newnumtriangles >= 1)
3106                 {
3107                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3108                         stop = false;
3109                 }
3110                 // if we couldn't find any lit triangles, exit early
3111                 if (stop)
3112                         break;
3113                 // now reduce the intensity for the next overbright pass
3114                 // we have to clamp to 0 here incase the drivers have improper
3115                 // handling of negative colors
3116                 // (some old drivers even have improper handling of >1 color)
3117                 stop = true;
3118                 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3119                 {
3120                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3121                         {
3122                                 c[0] = max(0, c[0] - 1);
3123                                 c[1] = max(0, c[1] - 1);
3124                                 c[2] = max(0, c[2] - 1);
3125                                 stop = false;
3126                         }
3127                         else
3128                                 VectorClear(c);
3129                 }
3130                 // another check...
3131                 if (stop)
3132                         break;
3133         }
3134 }
3135
3136 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3137 {
3138         // OpenGL 1.1 path (anything)
3139         float ambientcolorbase[3], diffusecolorbase[3];
3140         float ambientcolorpants[3], diffusecolorpants[3];
3141         float ambientcolorshirt[3], diffusecolorshirt[3];
3142         const float *surfacecolor = rsurface.texture->dlightcolor;
3143         const float *surfacepants = rsurface.colormap_pantscolor;
3144         const float *surfaceshirt = rsurface.colormap_shirtcolor;
3145         rtexture_t *basetexture = rsurface.texture->basetexture;
3146         rtexture_t *pantstexture = rsurface.texture->pantstexture;
3147         rtexture_t *shirttexture = rsurface.texture->shirttexture;
3148         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3149         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3150         ambientscale *= 2 * r_refdef.view.colorscale;
3151         diffusescale *= 2 * r_refdef.view.colorscale;
3152         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3153         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3154         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3155         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3156         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3157         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3158         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3159         rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3160         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3161         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3162         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3163         R_Mesh_TexBind(0, basetexture);
3164         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3165         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3166         switch(r_shadow_rendermode)
3167         {
3168         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3169                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3170                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3171                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3172                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3173                 break;
3174         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3175                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3176                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3177                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3178                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3179                 // fall through
3180         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3181                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3182                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3183                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3184                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3185                 break;
3186         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3187                 break;
3188         default:
3189                 break;
3190         }
3191         //R_Mesh_TexBind(0, basetexture);
3192         R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3193         if (dopants)
3194         {
3195                 R_Mesh_TexBind(0, pantstexture);
3196                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3197         }
3198         if (doshirt)
3199         {
3200                 R_Mesh_TexBind(0, shirttexture);
3201                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3202         }
3203 }
3204
3205 extern cvar_t gl_lightmaps;
3206 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3207 {
3208         float ambientscale, diffusescale, specularscale;
3209         qboolean negated;
3210         float lightcolor[3];
3211         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3212         ambientscale = rsurface.rtlight->ambientscale;
3213         diffusescale = rsurface.rtlight->diffusescale;
3214         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3215         if (!r_shadow_usenormalmap.integer)
3216         {
3217                 ambientscale += 1.0f * diffusescale;
3218                 diffusescale = 0;
3219                 specularscale = 0;
3220         }
3221         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3222                 return;
3223         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3224         if(negated)
3225         {
3226                 VectorNegate(lightcolor, lightcolor);
3227                 switch(vid.renderpath)
3228                 {
3229                 case RENDERPATH_GL11:
3230                 case RENDERPATH_GL13:
3231                 case RENDERPATH_GL20:
3232                 case RENDERPATH_GLES2:
3233                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3234                         break;
3235                 case RENDERPATH_D3D9:
3236 #ifdef SUPPORTD3D
3237                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3238 #endif
3239                         break;
3240                 case RENDERPATH_D3D10:
3241                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3242                         break;
3243                 case RENDERPATH_D3D11:
3244                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3245                         break;
3246                 case RENDERPATH_SOFT:
3247                         DPSOFTRAST_BlendSubtract(true);
3248                         break;
3249                 }
3250         }
3251         RSurf_SetupDepthAndCulling();
3252         switch (r_shadow_rendermode)
3253         {
3254         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3255                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3256                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3257                 break;
3258         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3259                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3260                 break;
3261         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3262         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3263         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3264         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3265                 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3266                 break;
3267         default:
3268                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3269                 break;
3270         }
3271         if(negated)
3272         {
3273                 switch(vid.renderpath)
3274                 {
3275                 case RENDERPATH_GL11:
3276                 case RENDERPATH_GL13:
3277                 case RENDERPATH_GL20:
3278                 case RENDERPATH_GLES2:
3279                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3280                         break;
3281                 case RENDERPATH_D3D9:
3282 #ifdef SUPPORTD3D
3283                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3284 #endif
3285                         break;
3286                 case RENDERPATH_D3D10:
3287                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3288                         break;
3289                 case RENDERPATH_D3D11:
3290                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3291                         break;
3292                 case RENDERPATH_SOFT:
3293                         DPSOFTRAST_BlendSubtract(false);
3294                         break;
3295                 }
3296         }
3297 }
3298
3299 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)
3300 {
3301         matrix4x4_t tempmatrix = *matrix;
3302         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3303
3304         // if this light has been compiled before, free the associated data
3305         R_RTLight_Uncompile(rtlight);
3306
3307         // clear it completely to avoid any lingering data
3308         memset(rtlight, 0, sizeof(*rtlight));
3309
3310         // copy the properties
3311         rtlight->matrix_lighttoworld = tempmatrix;
3312         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3313         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3314         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3315         VectorCopy(color, rtlight->color);
3316         rtlight->cubemapname[0] = 0;
3317         if (cubemapname && cubemapname[0])
3318                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3319         rtlight->shadow = shadow;
3320         rtlight->corona = corona;
3321         rtlight->style = style;
3322         rtlight->isstatic = isstatic;
3323         rtlight->coronasizescale = coronasizescale;
3324         rtlight->ambientscale = ambientscale;
3325         rtlight->diffusescale = diffusescale;
3326         rtlight->specularscale = specularscale;
3327         rtlight->flags = flags;
3328
3329         // compute derived data
3330         //rtlight->cullradius = rtlight->radius;
3331         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3332         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3333         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3334         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3335         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3336         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3337         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3338 }
3339
3340 // compiles rtlight geometry
3341 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3342 void R_RTLight_Compile(rtlight_t *rtlight)
3343 {
3344         int i;
3345         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3346         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3347         entity_render_t *ent = r_refdef.scene.worldentity;
3348         dp_model_t *model = r_refdef.scene.worldmodel;
3349         unsigned char *data;
3350         shadowmesh_t *mesh;
3351
3352         // compile the light
3353         rtlight->compiled = true;
3354         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3355         rtlight->static_numleafs = 0;
3356         rtlight->static_numleafpvsbytes = 0;
3357         rtlight->static_leaflist = NULL;
3358         rtlight->static_leafpvs = NULL;
3359         rtlight->static_numsurfaces = 0;
3360         rtlight->static_surfacelist = NULL;
3361         rtlight->static_shadowmap_receivers = 0x3F;
3362         rtlight->static_shadowmap_casters = 0x3F;
3363         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3364         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3365         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3366         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3367         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3368         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3369
3370         if (model && model->GetLightInfo)
3371         {
3372                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3373                 r_shadow_compilingrtlight = rtlight;
3374                 R_FrameData_SetMark();
3375                 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);
3376                 R_FrameData_ReturnToMark();
3377                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3378                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3379                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3380                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3381                 rtlight->static_numsurfaces = numsurfaces;
3382                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3383                 rtlight->static_numleafs = numleafs;
3384                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3385                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3386                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3387                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3388                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3389                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3390                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3391                 if (rtlight->static_numsurfaces)
3392                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3393                 if (rtlight->static_numleafs)
3394                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3395                 if (rtlight->static_numleafpvsbytes)
3396                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3397                 if (rtlight->static_numshadowtrispvsbytes)
3398                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3399                 if (rtlight->static_numlighttrispvsbytes)
3400                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3401                 R_FrameData_SetMark();
3402                 switch (rtlight->shadowmode)
3403                 {
3404                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3405                         if (model->CompileShadowMap && rtlight->shadow)
3406                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3407                         break;
3408                 default:
3409                         if (model->CompileShadowVolume && rtlight->shadow)
3410                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3411                         break;
3412                 }
3413                 R_FrameData_ReturnToMark();
3414                 // now we're done compiling the rtlight
3415                 r_shadow_compilingrtlight = NULL;
3416         }
3417
3418
3419         // use smallest available cullradius - box radius or light radius
3420         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3421         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3422
3423         shadowzpasstris = 0;
3424         if (rtlight->static_meshchain_shadow_zpass)
3425                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3426                         shadowzpasstris += mesh->numtriangles;
3427
3428         shadowzfailtris = 0;
3429         if (rtlight->static_meshchain_shadow_zfail)
3430                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3431                         shadowzfailtris += mesh->numtriangles;
3432
3433         lighttris = 0;
3434         if (rtlight->static_numlighttrispvsbytes)
3435                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3436                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3437                                 lighttris++;
3438
3439         shadowtris = 0;
3440         if (rtlight->static_numlighttrispvsbytes)
3441                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3442                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3443                                 shadowtris++;
3444
3445         if (developer_extra.integer)
3446                 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);
3447 }
3448
3449 void R_RTLight_Uncompile(rtlight_t *rtlight)
3450 {
3451         if (rtlight->compiled)
3452         {
3453                 if (rtlight->static_meshchain_shadow_zpass)
3454                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3455                 rtlight->static_meshchain_shadow_zpass = NULL;
3456                 if (rtlight->static_meshchain_shadow_zfail)
3457                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3458                 rtlight->static_meshchain_shadow_zfail = NULL;
3459                 if (rtlight->static_meshchain_shadow_shadowmap)
3460                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3461                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3462                 // these allocations are grouped
3463                 if (rtlight->static_surfacelist)
3464                         Mem_Free(rtlight->static_surfacelist);
3465                 rtlight->static_numleafs = 0;
3466                 rtlight->static_numleafpvsbytes = 0;
3467                 rtlight->static_leaflist = NULL;
3468                 rtlight->static_leafpvs = NULL;
3469                 rtlight->static_numsurfaces = 0;
3470                 rtlight->static_surfacelist = NULL;
3471                 rtlight->static_numshadowtrispvsbytes = 0;
3472                 rtlight->static_shadowtrispvs = NULL;
3473                 rtlight->static_numlighttrispvsbytes = 0;
3474                 rtlight->static_lighttrispvs = NULL;
3475                 rtlight->compiled = false;
3476         }
3477 }
3478
3479 void R_Shadow_UncompileWorldLights(void)
3480 {
3481         size_t lightindex;
3482         dlight_t *light;
3483         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3484         for (lightindex = 0;lightindex < range;lightindex++)
3485         {
3486                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3487                 if (!light)
3488                         continue;
3489                 R_RTLight_Uncompile(&light->rtlight);
3490         }
3491 }
3492
3493 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3494 {
3495         int i, j;
3496         mplane_t plane;
3497         // reset the count of frustum planes
3498         // see rtlight->cached_frustumplanes definition for how much this array
3499         // can hold
3500         rtlight->cached_numfrustumplanes = 0;
3501
3502         // haven't implemented a culling path for ortho rendering
3503         if (!r_refdef.view.useperspective)
3504         {
3505                 // check if the light is on screen and copy the 4 planes if it is
3506                 for (i = 0;i < 4;i++)
3507                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3508                                 break;
3509                 if (i == 4)
3510                         for (i = 0;i < 4;i++)
3511                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3512                 return;
3513         }
3514
3515 #if 1
3516         // generate a deformed frustum that includes the light origin, this is
3517         // used to cull shadow casting surfaces that can not possibly cast a
3518         // shadow onto the visible light-receiving surfaces, which can be a
3519         // performance gain
3520         //
3521         // if the light origin is onscreen the result will be 4 planes exactly
3522         // if the light origin is offscreen on only one axis the result will
3523         // be exactly 5 planes (split-side case)
3524         // if the light origin is offscreen on two axes the result will be
3525         // exactly 4 planes (stretched corner case)
3526         for (i = 0;i < 4;i++)
3527         {
3528                 // quickly reject standard frustum planes that put the light
3529                 // origin outside the frustum
3530                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3531                         continue;
3532                 // copy the plane
3533                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3534         }
3535         // if all the standard frustum planes were accepted, the light is onscreen
3536         // otherwise we need to generate some more planes below...
3537         if (rtlight->cached_numfrustumplanes < 4)
3538         {
3539                 // at least one of the stock frustum planes failed, so we need to
3540                 // create one or two custom planes to enclose the light origin
3541                 for (i = 0;i < 4;i++)
3542                 {
3543                         // create a plane using the view origin and light origin, and a
3544                         // single point from the frustum corner set
3545                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3546                         VectorNormalize(plane.normal);
3547                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3548                         // see if this plane is backwards and flip it if so
3549                         for (j = 0;j < 4;j++)
3550                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3551                                         break;
3552                         if (j < 4)
3553                         {
3554                                 VectorNegate(plane.normal, plane.normal);
3555                                 plane.dist *= -1;
3556                                 // flipped plane, test again to see if it is now valid
3557                                 for (j = 0;j < 4;j++)
3558                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3559                                                 break;
3560                                 // if the plane is still not valid, then it is dividing the
3561                                 // frustum and has to be rejected
3562                                 if (j < 4)
3563                                         continue;
3564                         }
3565                         // we have created a valid plane, compute extra info
3566                         PlaneClassify(&plane);
3567                         // copy the plane
3568                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3569 #if 1
3570                         // if we've found 5 frustum planes then we have constructed a
3571                         // proper split-side case and do not need to keep searching for
3572                         // planes to enclose the light origin
3573                         if (rtlight->cached_numfrustumplanes == 5)
3574                                 break;
3575 #endif
3576                 }
3577         }
3578 #endif
3579
3580 #if 0
3581         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3582         {
3583                 plane = rtlight->cached_frustumplanes[i];
3584                 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));
3585         }
3586 #endif
3587
3588 #if 0
3589         // now add the light-space box planes if the light box is rotated, as any
3590         // caster outside the oriented light box is irrelevant (even if it passed
3591         // the worldspace light box, which is axial)
3592         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3593         {
3594                 for (i = 0;i < 6;i++)
3595                 {
3596                         vec3_t v;
3597                         VectorClear(v);
3598                         v[i >> 1] = (i & 1) ? -1 : 1;
3599                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3600                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3601                         plane.dist = VectorNormalizeLength(plane.normal);
3602                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3603                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3604                 }
3605         }
3606 #endif
3607
3608 #if 0
3609         // add the world-space reduced box planes
3610         for (i = 0;i < 6;i++)
3611         {
3612                 VectorClear(plane.normal);
3613                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3614                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3615                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3616         }
3617 #endif
3618
3619 #if 0
3620         {
3621         int j, oldnum;
3622         vec3_t points[8];
3623         vec_t bestdist;
3624         // reduce all plane distances to tightly fit the rtlight cull box, which
3625         // is in worldspace
3626         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3627         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3628         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3629         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3630         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3631         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3632         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3633         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3634         oldnum = rtlight->cached_numfrustumplanes;
3635         rtlight->cached_numfrustumplanes = 0;
3636         for (j = 0;j < oldnum;j++)
3637         {
3638                 // find the nearest point on the box to this plane
3639                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3640                 for (i = 1;i < 8;i++)
3641                 {
3642                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3643                         if (bestdist > dist)
3644                                 bestdist = dist;
3645                 }
3646                 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);
3647                 // if the nearest point is near or behind the plane, we want this
3648                 // plane, otherwise the plane is useless as it won't cull anything
3649                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3650                 {
3651                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3652                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3653                 }
3654         }
3655         }
3656 #endif
3657 }
3658
3659 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3660 {
3661         shadowmesh_t *mesh;
3662
3663         RSurf_ActiveWorldEntity();
3664
3665         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3666         {
3667                 CHECKGLERROR
3668                 GL_CullFace(GL_NONE);
3669                 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3670                 for (;mesh;mesh = mesh->next)
3671                 {
3672                         if (!mesh->sidetotals[r_shadow_shadowmapside])
3673                                 continue;
3674                         r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3675                         if (mesh->vertex3fbuffer)
3676                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3677                         else
3678                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3679                         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);
3680                 }
3681                 CHECKGLERROR
3682         }
3683         else if (r_refdef.scene.worldentity->model)
3684                 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);
3685
3686         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3687 }
3688
3689 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3690 {
3691         qboolean zpass = false;
3692         shadowmesh_t *mesh;
3693         int t, tend;
3694         int surfacelistindex;
3695         msurface_t *surface;
3696
3697         // if triangle neighbors are disabled, shadowvolumes are disabled
3698         if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3699                 return;
3700
3701         RSurf_ActiveWorldEntity();
3702
3703         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3704         {
3705                 CHECKGLERROR
3706                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3707                 {
3708                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3709                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3710                 }
3711                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3712                 for (;mesh;mesh = mesh->next)
3713                 {
3714                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3715                         if (mesh->vertex3fbuffer)
3716                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3717                         else
3718                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3719                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3720                         {
3721                                 // increment stencil if frontface is infront of depthbuffer
3722                                 GL_CullFace(r_refdef.view.cullface_back);
3723                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3724                                 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);
3725                                 // decrement stencil if backface is infront of depthbuffer
3726                                 GL_CullFace(r_refdef.view.cullface_front);
3727                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3728                         }
3729                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3730                         {
3731                                 // decrement stencil if backface is behind depthbuffer
3732                                 GL_CullFace(r_refdef.view.cullface_front);
3733                                 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3734                                 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);
3735                                 // increment stencil if frontface is behind depthbuffer
3736                                 GL_CullFace(r_refdef.view.cullface_back);
3737                                 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3738                         }
3739                         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);
3740                 }
3741                 CHECKGLERROR
3742         }
3743         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3744         {
3745                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3746                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3747                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3748                 {
3749                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3750                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3751                                 if (CHECKPVSBIT(trispvs, t))
3752                                         shadowmarklist[numshadowmark++] = t;
3753                 }
3754                 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);
3755         }
3756         else if (numsurfaces)
3757         {
3758                 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);
3759         }
3760
3761         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3762 }
3763
3764 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3765 {
3766         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3767         vec_t relativeshadowradius;
3768         RSurf_ActiveModelEntity(ent, false, false, false);
3769         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3770         // we need to re-init the shader for each entity because the matrix changed
3771         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3772         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3773         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3774         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3775         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3776         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3777         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3778         switch (r_shadow_rendermode)
3779         {
3780         case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3781                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3782                 break;
3783         default:
3784                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3785                 break;
3786         }
3787         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3788 }
3789
3790 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3791 {
3792         // set up properties for rendering light onto this entity
3793         RSurf_ActiveModelEntity(ent, true, true, false);
3794         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3795         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3796         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3797         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3798 }
3799
3800 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3801 {
3802         if (!r_refdef.scene.worldmodel->DrawLight)
3803                 return;
3804
3805         // set up properties for rendering light onto this entity
3806         RSurf_ActiveWorldEntity();
3807         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3808         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3809         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3810         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3811
3812         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3813
3814         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3815 }
3816
3817 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3818 {
3819         dp_model_t *model = ent->model;
3820         if (!model->DrawLight)
3821                 return;
3822
3823         R_Shadow_SetupEntityLight(ent);
3824
3825         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3826
3827         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3828 }
3829
3830 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3831 {
3832         int i;
3833         float f;
3834         int numleafs, numsurfaces;
3835         int *leaflist, *surfacelist;
3836         unsigned char *leafpvs;
3837         unsigned char *shadowtrispvs;
3838         unsigned char *lighttrispvs;
3839         //unsigned char *surfacesides;
3840         int numlightentities;
3841         int numlightentities_noselfshadow;
3842         int numshadowentities;
3843         int numshadowentities_noselfshadow;
3844         static entity_render_t *lightentities[MAX_EDICTS];
3845         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3846         static entity_render_t *shadowentities[MAX_EDICTS];
3847         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3848         qboolean nolight;
3849
3850         rtlight->draw = false;
3851
3852         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3853         // skip lights that are basically invisible (color 0 0 0)
3854         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3855
3856         // loading is done before visibility checks because loading should happen
3857         // all at once at the start of a level, not when it stalls gameplay.
3858         // (especially important to benchmarks)
3859         // compile light
3860         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3861         {
3862                 if (rtlight->compiled)
3863                         R_RTLight_Uncompile(rtlight);
3864                 R_RTLight_Compile(rtlight);
3865         }
3866
3867         // load cubemap
3868         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3869
3870         // look up the light style value at this time
3871         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3872         VectorScale(rtlight->color, f, rtlight->currentcolor);
3873         /*
3874         if (rtlight->selected)
3875         {
3876                 f = 2 + sin(realtime * M_PI * 4.0);
3877                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3878         }
3879         */
3880
3881         // if lightstyle is currently off, don't draw the light
3882         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3883                 return;
3884
3885         // skip processing on corona-only lights
3886         if (nolight)
3887                 return;
3888
3889         // if the light box is offscreen, skip it
3890         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3891                 return;
3892
3893         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3894         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3895
3896         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3897
3898         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3899         {
3900                 // compiled light, world available and can receive realtime lighting
3901                 // retrieve leaf information
3902                 numleafs = rtlight->static_numleafs;
3903                 leaflist = rtlight->static_leaflist;
3904                 leafpvs = rtlight->static_leafpvs;
3905                 numsurfaces = rtlight->static_numsurfaces;
3906                 surfacelist = rtlight->static_surfacelist;
3907                 //surfacesides = NULL;
3908                 shadowtrispvs = rtlight->static_shadowtrispvs;
3909                 lighttrispvs = rtlight->static_lighttrispvs;
3910         }
3911         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3912         {
3913                 // dynamic light, world available and can receive realtime lighting
3914                 // calculate lit surfaces and leafs
3915                 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);
3916                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3917                 leaflist = r_shadow_buffer_leaflist;
3918                 leafpvs = r_shadow_buffer_leafpvs;
3919                 surfacelist = r_shadow_buffer_surfacelist;
3920                 //surfacesides = r_shadow_buffer_surfacesides;
3921                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3922                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3923                 // if the reduced leaf bounds are offscreen, skip it
3924                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3925                         return;
3926         }
3927         else
3928         {
3929                 // no world
3930                 numleafs = 0;
3931                 leaflist = NULL;
3932                 leafpvs = NULL;
3933                 numsurfaces = 0;
3934                 surfacelist = NULL;
3935                 //surfacesides = NULL;
3936                 shadowtrispvs = NULL;
3937                 lighttrispvs = NULL;
3938         }
3939         // check if light is illuminating any visible leafs
3940         if (numleafs)
3941         {
3942                 for (i = 0;i < numleafs;i++)
3943                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3944                                 break;
3945                 if (i == numleafs)
3946                         return;
3947         }
3948
3949         // make a list of lit entities and shadow casting entities
3950         numlightentities = 0;
3951         numlightentities_noselfshadow = 0;
3952         numshadowentities = 0;
3953         numshadowentities_noselfshadow = 0;
3954
3955         // add dynamic entities that are lit by the light
3956         for (i = 0;i < r_refdef.scene.numentities;i++)
3957         {
3958                 dp_model_t *model;
3959                 entity_render_t *ent = r_refdef.scene.entities[i];
3960                 vec3_t org;
3961                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3962                         continue;
3963                 // skip the object entirely if it is not within the valid
3964                 // shadow-casting region (which includes the lit region)
3965                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3966                         continue;
3967                 if (!(model = ent->model))
3968                         continue;
3969                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3970                 {
3971                         // this entity wants to receive light, is visible, and is
3972                         // inside the light box
3973                         // TODO: check if the surfaces in the model can receive light
3974                         // so now check if it's in a leaf seen by the light
3975                         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))
3976                                 continue;
3977                         if (ent->flags & RENDER_NOSELFSHADOW)
3978                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3979                         else
3980                                 lightentities[numlightentities++] = ent;
3981                         // since it is lit, it probably also casts a shadow...
3982                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3983                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3984                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3985                         {
3986                                 // note: exterior models without the RENDER_NOSELFSHADOW
3987                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3988                                 // are lit normally, this means that they are
3989                                 // self-shadowing but do not shadow other
3990                                 // RENDER_NOSELFSHADOW entities such as the gun
3991                                 // (very weird, but keeps the player shadow off the gun)
3992                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3993                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3994                                 else
3995                                         shadowentities[numshadowentities++] = ent;
3996                         }
3997                 }
3998                 else if (ent->flags & RENDER_SHADOW)
3999                 {
4000                         // this entity is not receiving light, but may still need to
4001                         // cast a shadow...
4002                         // TODO: check if the surfaces in the model can cast shadow
4003                         // now check if it is in a leaf seen by the light
4004                         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))
4005                                 continue;
4006                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4007                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4008                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4009                         {
4010                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4011                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4012                                 else
4013                                         shadowentities[numshadowentities++] = ent;
4014                         }
4015                 }
4016         }
4017
4018         // return if there's nothing at all to light
4019         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4020                 return;
4021
4022         // count this light in the r_speeds
4023         r_refdef.stats.lights++;
4024
4025         // flag it as worth drawing later
4026         rtlight->draw = true;
4027
4028         // cache all the animated entities that cast a shadow but are not visible
4029         for (i = 0;i < numshadowentities;i++)
4030                 if (!shadowentities[i]->animcache_vertex3f)
4031                         R_AnimCache_GetEntity(shadowentities[i], false, false);
4032         for (i = 0;i < numshadowentities_noselfshadow;i++)
4033                 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
4034                         R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4035
4036         // allocate some temporary memory for rendering this light later in the frame
4037         // reusable buffers need to be copied, static data can be used as-is
4038         rtlight->cached_numlightentities               = numlightentities;
4039         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
4040         rtlight->cached_numshadowentities              = numshadowentities;
4041         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4042         rtlight->cached_numsurfaces                    = numsurfaces;
4043         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4044         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4045         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4046         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4047         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4048         {
4049                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4050                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4051                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4052                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4053                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4054         }
4055         else
4056         {
4057                 // compiled light data
4058                 rtlight->cached_shadowtrispvs = shadowtrispvs;
4059                 rtlight->cached_lighttrispvs = lighttrispvs;
4060                 rtlight->cached_surfacelist = surfacelist;
4061         }
4062 }
4063
4064 void R_Shadow_DrawLight(rtlight_t *rtlight)
4065 {
4066         int i;
4067         int numsurfaces;
4068         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4069         int numlightentities;
4070         int numlightentities_noselfshadow;
4071         int numshadowentities;
4072         int numshadowentities_noselfshadow;
4073         entity_render_t **lightentities;
4074         entity_render_t **lightentities_noselfshadow;
4075         entity_render_t **shadowentities;
4076         entity_render_t **shadowentities_noselfshadow;
4077         int *surfacelist;
4078         static unsigned char entitysides[MAX_EDICTS];
4079         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4080         vec3_t nearestpoint;
4081         vec_t distance;
4082         qboolean castshadows;
4083         int lodlinear;
4084
4085         // check if we cached this light this frame (meaning it is worth drawing)
4086         if (!rtlight->draw)
4087                 return;
4088
4089         numlightentities = rtlight->cached_numlightentities;
4090         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4091         numshadowentities = rtlight->cached_numshadowentities;
4092         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4093         numsurfaces = rtlight->cached_numsurfaces;
4094         lightentities = rtlight->cached_lightentities;
4095         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4096         shadowentities = rtlight->cached_shadowentities;
4097         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4098         shadowtrispvs = rtlight->cached_shadowtrispvs;
4099         lighttrispvs = rtlight->cached_lighttrispvs;
4100         surfacelist = rtlight->cached_surfacelist;
4101
4102         // set up a scissor rectangle for this light
4103         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4104                 return;
4105
4106         // don't let sound skip if going slow
4107         if (r_refdef.scene.extraupdate)
4108                 S_ExtraUpdate ();
4109
4110         // make this the active rtlight for rendering purposes
4111         R_Shadow_RenderMode_ActiveLight(rtlight);
4112
4113         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4114         {
4115                 // optionally draw visible shape of the shadow volumes
4116                 // for performance analysis by level designers
4117                 R_Shadow_RenderMode_VisibleShadowVolumes();
4118                 if (numsurfaces)
4119                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4120                 for (i = 0;i < numshadowentities;i++)
4121                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4122                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4123                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4124                 R_Shadow_RenderMode_VisibleLighting(false, false);
4125         }
4126
4127         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4128         {
4129                 // optionally draw the illuminated areas
4130                 // for performance analysis by level designers
4131                 R_Shadow_RenderMode_VisibleLighting(false, false);
4132                 if (numsurfaces)
4133                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4134                 for (i = 0;i < numlightentities;i++)
4135                         R_Shadow_DrawEntityLight(lightentities[i]);
4136                 for (i = 0;i < numlightentities_noselfshadow;i++)
4137                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4138         }
4139
4140         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4141
4142         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4143         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4144         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4145         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4146
4147         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4148         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4149         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4150
4151         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4152         {
4153                 float borderbias;
4154                 int side;
4155                 int size;
4156                 int castermask = 0;
4157                 int receivermask = 0;
4158                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4159                 Matrix4x4_Abs(&radiustolight);
4160
4161                 r_shadow_shadowmaplod = 0;
4162                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4163                         if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4164                                 r_shadow_shadowmaplod = i;
4165
4166                 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4167                         
4168                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4169
4170                 surfacesides = NULL;
4171                 if (numsurfaces)
4172                 {
4173                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4174                         {
4175                                 castermask = rtlight->static_shadowmap_casters;
4176                                 receivermask = rtlight->static_shadowmap_receivers;
4177                         }
4178                         else
4179                         {
4180                                 surfacesides = r_shadow_buffer_surfacesides;
4181                                 for(i = 0;i < numsurfaces;i++)
4182                                 {
4183                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4184                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
4185                                         castermask |= surfacesides[i];
4186                                         receivermask |= surfacesides[i];
4187                                 }
4188                         }
4189                 }
4190                 if (receivermask < 0x3F) 
4191                 {
4192                         for (i = 0;i < numlightentities;i++)
4193                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4194                         if (receivermask < 0x3F)
4195                                 for(i = 0; i < numlightentities_noselfshadow;i++)
4196                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4197                 }
4198
4199                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4200
4201                 if (receivermask)
4202                 {
4203                         for (i = 0;i < numshadowentities;i++)
4204                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4205                         for (i = 0;i < numshadowentities_noselfshadow;i++)
4206                                 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
4207                 }
4208
4209                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4210
4211                 // render shadow casters into 6 sided depth texture
4212                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4213                 {
4214                         R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4215                         if (! (castermask & (1 << side))) continue;
4216                         if (numsurfaces)
4217                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4218                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4219                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
4220                 }
4221
4222                 if (numlightentities_noselfshadow)
4223                 {
4224                         // render lighting using the depth texture as shadowmap
4225                         // draw lighting in the unmasked areas
4226                         R_Shadow_RenderMode_Lighting(false, false, true);
4227                         for (i = 0;i < numlightentities_noselfshadow;i++)
4228                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4229                 }
4230
4231                 // render shadow casters into 6 sided depth texture
4232                 if (numshadowentities_noselfshadow)
4233                 {
4234                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4235                         {
4236                                 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4237                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4238                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4239                         }
4240                 }
4241
4242                 // render lighting using the depth texture as shadowmap
4243                 // draw lighting in the unmasked areas
4244                 R_Shadow_RenderMode_Lighting(false, false, true);
4245                 // draw lighting in the unmasked areas
4246                 if (numsurfaces)
4247                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4248                 for (i = 0;i < numlightentities;i++)
4249                         R_Shadow_DrawEntityLight(lightentities[i]);
4250         }
4251         else if (castshadows && vid.stencil)
4252         {
4253                 // draw stencil shadow volumes to mask off pixels that are in shadow
4254                 // so that they won't receive lighting
4255                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4256                 R_Shadow_ClearStencil();
4257
4258                 if (numsurfaces)
4259                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4260                 for (i = 0;i < numshadowentities;i++)
4261                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4262
4263                 // draw lighting in the unmasked areas
4264                 R_Shadow_RenderMode_Lighting(true, false, false);
4265                 for (i = 0;i < numlightentities_noselfshadow;i++)
4266                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4267
4268                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4269                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4270
4271                 // draw lighting in the unmasked areas
4272                 R_Shadow_RenderMode_Lighting(true, false, false);
4273                 if (numsurfaces)
4274                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4275                 for (i = 0;i < numlightentities;i++)
4276                         R_Shadow_DrawEntityLight(lightentities[i]);
4277         }
4278         else
4279         {
4280                 // draw lighting in the unmasked areas
4281                 R_Shadow_RenderMode_Lighting(false, false, false);
4282                 if (numsurfaces)
4283                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4284                 for (i = 0;i < numlightentities;i++)
4285                         R_Shadow_DrawEntityLight(lightentities[i]);
4286                 for (i = 0;i < numlightentities_noselfshadow;i++)
4287                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4288         }
4289
4290         if (r_shadow_usingdeferredprepass)
4291         {
4292                 // when rendering deferred lighting, we simply rasterize the box
4293                 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4294                         R_Shadow_RenderMode_DrawDeferredLight(false, true);
4295                 else if (castshadows && vid.stencil)
4296                         R_Shadow_RenderMode_DrawDeferredLight(true, false);
4297                 else
4298                         R_Shadow_RenderMode_DrawDeferredLight(false, false);
4299         }
4300
4301         if (r_shadow_particletrace.integer)
4302                 R_Shadow_RenderParticlesForLight(rtlight);
4303 }
4304
4305 static void R_Shadow_FreeDeferred(void)
4306 {
4307         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4308         r_shadow_prepassgeometryfbo = 0;
4309
4310         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4311         r_shadow_prepasslightingdiffusespecularfbo = 0;
4312
4313         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4314         r_shadow_prepasslightingdiffusefbo = 0;
4315
4316         if (r_shadow_prepassgeometrydepthtexture)
4317                 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4318         r_shadow_prepassgeometrydepthtexture = NULL;
4319
4320         if (r_shadow_prepassgeometrydepthcolortexture)
4321                 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4322         r_shadow_prepassgeometrydepthcolortexture = NULL;
4323
4324         if (r_shadow_prepassgeometrynormalmaptexture)
4325                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4326         r_shadow_prepassgeometrynormalmaptexture = NULL;
4327
4328         if (r_shadow_prepasslightingdiffusetexture)
4329                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4330         r_shadow_prepasslightingdiffusetexture = NULL;
4331
4332         if (r_shadow_prepasslightingspeculartexture)
4333                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4334         r_shadow_prepasslightingspeculartexture = NULL;
4335 }
4336
4337 void R_Shadow_DrawPrepass(void)
4338 {
4339         int i;
4340         int flag;
4341         int lnum;
4342         size_t lightindex;
4343         dlight_t *light;
4344         size_t range;
4345         entity_render_t *ent;
4346         float clearcolor[4];
4347
4348         R_Mesh_ResetTextureState();
4349         GL_DepthMask(true);
4350         GL_ColorMask(1,1,1,1);
4351         GL_BlendFunc(GL_ONE, GL_ZERO);
4352         GL_Color(1,1,1,1);
4353         GL_DepthTest(true);
4354         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4355         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4356         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4357         if (r_timereport_active)
4358                 R_TimeReport("prepasscleargeom");
4359
4360         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4361                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4362         if (r_timereport_active)
4363                 R_TimeReport("prepassworld");
4364
4365         for (i = 0;i < r_refdef.scene.numentities;i++)
4366         {
4367                 if (!r_refdef.viewcache.entityvisible[i])
4368                         continue;
4369                 ent = r_refdef.scene.entities[i];
4370                 if (ent->model && ent->model->DrawPrepass != NULL)
4371                         ent->model->DrawPrepass(ent);
4372         }
4373
4374         if (r_timereport_active)
4375                 R_TimeReport("prepassmodels");
4376
4377         GL_DepthMask(false);
4378         GL_ColorMask(1,1,1,1);
4379         GL_Color(1,1,1,1);
4380         GL_DepthTest(true);
4381         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4382         Vector4Set(clearcolor, 0, 0, 0, 0);
4383         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4384         if (r_timereport_active)
4385                 R_TimeReport("prepassclearlit");
4386
4387         R_Shadow_RenderMode_Begin();
4388
4389         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4390         if (r_shadow_debuglight.integer >= 0)
4391         {
4392                 lightindex = r_shadow_debuglight.integer;
4393                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4394                 if (light && (light->flags & flag) && light->rtlight.draw)
4395                         R_Shadow_DrawLight(&light->rtlight);
4396         }
4397         else
4398         {
4399                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4400                 for (lightindex = 0;lightindex < range;lightindex++)
4401                 {
4402                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4403                         if (light && (light->flags & flag) && light->rtlight.draw)
4404                                 R_Shadow_DrawLight(&light->rtlight);
4405                 }
4406         }
4407         if (r_refdef.scene.rtdlight)
4408                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4409                         if (r_refdef.scene.lights[lnum]->draw)
4410                                 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4411
4412         R_Mesh_ResetRenderTargets();
4413
4414         R_Shadow_RenderMode_End();
4415
4416         if (r_timereport_active)
4417                 R_TimeReport("prepasslights");
4418 }
4419
4420 void R_Shadow_DrawLightSprites(void);
4421 void R_Shadow_PrepareLights(void)
4422 {
4423         int flag;
4424         int lnum;
4425         size_t lightindex;
4426         dlight_t *light;
4427         size_t range;
4428         float f;
4429         GLenum status;
4430
4431         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4432                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4433                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || 
4434                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4435                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4436                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4437                 R_Shadow_FreeShadowMaps();
4438
4439         r_shadow_usingshadowmaportho = false;
4440
4441         switch (vid.renderpath)
4442         {
4443         case RENDERPATH_GL20:
4444         case RENDERPATH_D3D9:
4445         case RENDERPATH_D3D10:
4446         case RENDERPATH_D3D11:
4447         case RENDERPATH_SOFT:
4448         case RENDERPATH_GLES2:
4449                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4450                 {
4451                         r_shadow_usingdeferredprepass = false;
4452                         if (r_shadow_prepass_width)
4453                                 R_Shadow_FreeDeferred();
4454                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4455                         break;
4456                 }
4457
4458                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4459                 {
4460                         R_Shadow_FreeDeferred();
4461
4462                         r_shadow_usingdeferredprepass = true;
4463                         r_shadow_prepass_width = vid.width;
4464                         r_shadow_prepass_height = vid.height;
4465                         r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4466                         switch (vid.renderpath)
4467                         {
4468                         case RENDERPATH_D3D9:
4469                                 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);
4470                                 break;
4471                         default:
4472                                 break;
4473                         }
4474                         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);
4475                         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);
4476                         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);
4477
4478                         // set up the geometry pass fbo (depth + normalmap)
4479                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4480                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4481                         // render depth into one texture and normalmap into the other
4482                         if (qglDrawBuffersARB)
4483                         {
4484                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4485                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4486                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4487                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4488                                 {
4489                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4490                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4491                                         r_shadow_usingdeferredprepass = false;
4492                                 }
4493                         }
4494
4495                         // set up the lighting pass fbo (diffuse + specular)
4496                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4497                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4498                         // render diffuse into one texture and specular into another,
4499                         // with depth and normalmap bound as textures,
4500                         // with depth bound as attachment as well
4501                         if (qglDrawBuffersARB)
4502                         {
4503                                 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4504                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4505                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4506                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4507                                 {
4508                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4509                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4510                                         r_shadow_usingdeferredprepass = false;
4511                                 }
4512                         }
4513
4514                         // set up the lighting pass fbo (diffuse)
4515                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4516                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4517                         // render diffuse into one texture,
4518                         // with depth and normalmap bound as textures,
4519                         // with depth bound as attachment as well
4520                         if (qglDrawBuffersARB)
4521                         {
4522                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4523                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4524                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4525                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4526                                 {
4527                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4528                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4529                                         r_shadow_usingdeferredprepass = false;
4530                                 }
4531                         }
4532                 }
4533                 break;
4534         case RENDERPATH_GL13:
4535         case RENDERPATH_GL11:
4536                 r_shadow_usingdeferredprepass = false;
4537                 break;
4538         }
4539
4540         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);
4541
4542         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4543         if (r_shadow_debuglight.integer >= 0)
4544         {
4545                 lightindex = r_shadow_debuglight.integer;
4546                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4547                 if (light && (light->flags & flag))
4548                         R_Shadow_PrepareLight(&light->rtlight);
4549         }
4550         else
4551         {
4552                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4553                 for (lightindex = 0;lightindex < range;lightindex++)
4554                 {
4555                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4556                         if (light && (light->flags & flag))
4557                                 R_Shadow_PrepareLight(&light->rtlight);
4558                 }
4559         }
4560         if (r_refdef.scene.rtdlight)
4561         {
4562                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4563                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4564         }
4565         else if(gl_flashblend.integer)
4566         {
4567                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4568                 {
4569                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4570                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4571                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4572                 }
4573         }
4574
4575         if (r_editlights.integer)
4576                 R_Shadow_DrawLightSprites();
4577
4578         R_Shadow_UpdateBounceGridTexture();
4579 }
4580
4581 void R_Shadow_DrawLights(void)
4582 {
4583         int flag;
4584         int lnum;
4585         size_t lightindex;
4586         dlight_t *light;
4587         size_t range;
4588
4589         R_Shadow_RenderMode_Begin();
4590
4591         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4592         if (r_shadow_debuglight.integer >= 0)
4593         {
4594                 lightindex = r_shadow_debuglight.integer;
4595                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4596                 if (light && (light->flags & flag))
4597                         R_Shadow_DrawLight(&light->rtlight);
4598         }
4599         else
4600         {
4601                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4602                 for (lightindex = 0;lightindex < range;lightindex++)
4603                 {
4604                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4605                         if (light && (light->flags & flag))
4606                                 R_Shadow_DrawLight(&light->rtlight);
4607                 }
4608         }
4609         if (r_refdef.scene.rtdlight)
4610                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4611                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4612
4613         R_Shadow_RenderMode_End();
4614 }
4615
4616 extern const float r_screenvertex3f[12];
4617 extern void R_SetupView(qboolean allowwaterclippingplane);
4618 extern void R_ResetViewRendering3D(void);
4619 extern void R_ResetViewRendering2D(void);
4620 extern cvar_t r_shadows;
4621 extern cvar_t r_shadows_darken;
4622 extern cvar_t r_shadows_drawafterrtlighting;
4623 extern cvar_t r_shadows_castfrombmodels;
4624 extern cvar_t r_shadows_throwdistance;
4625 extern cvar_t r_shadows_throwdirection;
4626 extern cvar_t r_shadows_focus;
4627 extern cvar_t r_shadows_shadowmapscale;
4628
4629 void R_Shadow_PrepareModelShadows(void)
4630 {
4631         int i;
4632         float scale, size, radius, dot1, dot2;
4633         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4634         entity_render_t *ent;
4635
4636         if (!r_refdef.scene.numentities)
4637                 return;
4638
4639         switch (r_shadow_shadowmode)
4640         {
4641         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4642                 if (r_shadows.integer >= 2) 
4643                         break;
4644                 // fall through
4645         case R_SHADOW_SHADOWMODE_STENCIL:
4646                 for (i = 0;i < r_refdef.scene.numentities;i++)
4647                 {
4648                         ent = r_refdef.scene.entities[i];
4649                         if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4650                                 R_AnimCache_GetEntity(ent, false, false);
4651                 }
4652                 return;
4653         default:
4654                 return;
4655         }
4656
4657         size = 2*r_shadow_shadowmapmaxsize;
4658         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4659         radius = 0.5f * size / scale;
4660
4661         Math_atov(r_shadows_throwdirection.string, shadowdir);
4662         VectorNormalize(shadowdir);
4663         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4664         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4665         if (fabs(dot1) <= fabs(dot2))
4666                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4667         else
4668                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4669         VectorNormalize(shadowforward);
4670         CrossProduct(shadowdir, shadowforward, shadowright);
4671         Math_atov(r_shadows_focus.string, shadowfocus);
4672         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4673         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4674         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4675         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4676         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4677                 dot1 = 1;
4678         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4679
4680         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4681         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4682         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4683         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4684         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4685         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4686
4687         for (i = 0;i < r_refdef.scene.numentities;i++)
4688         {
4689                 ent = r_refdef.scene.entities[i];
4690                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4691                         continue;
4692                 // cast shadows from anything of the map (submodels are optional)
4693                 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4694                         R_AnimCache_GetEntity(ent, false, false);
4695         }
4696 }
4697
4698 void R_DrawModelShadowMaps(void)
4699 {
4700         int i;
4701         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4702         entity_render_t *ent;
4703         vec3_t relativelightorigin;
4704         vec3_t relativelightdirection, relativeforward, relativeright;
4705         vec3_t relativeshadowmins, relativeshadowmaxs;
4706         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4707         float m[12];
4708         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4709         r_viewport_t viewport;
4710         GLuint fbo = 0;
4711         float clearcolor[4];
4712
4713         if (!r_refdef.scene.numentities)
4714                 return;
4715
4716         switch (r_shadow_shadowmode)
4717         {
4718         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4719                 break;
4720         default:
4721                 return;
4722         }
4723
4724         R_ResetViewRendering3D();
4725         R_Shadow_RenderMode_Begin();
4726         R_Shadow_RenderMode_ActiveLight(NULL);
4727
4728         switch (r_shadow_shadowmode)
4729         {
4730         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4731                 if (!r_shadow_shadowmap2dtexture)
4732                         R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4733                 fbo = r_shadow_fbo2d;
4734                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4735                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4736                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4737                 break;
4738         default:
4739                 break;
4740         }
4741
4742         size = 2*r_shadow_shadowmapmaxsize;
4743         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4744         radius = 0.5f / scale;
4745         nearclip = -r_shadows_throwdistance.value;
4746         farclip = r_shadows_throwdistance.value;
4747         bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4748
4749         r_shadow_shadowmap_parameters[0] = size;
4750         r_shadow_shadowmap_parameters[1] = size;
4751         r_shadow_shadowmap_parameters[2] = 1.0;
4752         r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4753
4754         Math_atov(r_shadows_throwdirection.string, shadowdir);
4755         VectorNormalize(shadowdir);
4756         Math_atov(r_shadows_focus.string, shadowfocus);
4757         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4758         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4759         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4760         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4761         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4762         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4763         if (fabs(dot1) <= fabs(dot2)) 
4764                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4765         else
4766                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4767         VectorNormalize(shadowforward);
4768         VectorM(scale, shadowforward, &m[0]);
4769         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4770                 dot1 = 1;
4771         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4772         CrossProduct(shadowdir, shadowforward, shadowright);
4773         VectorM(scale, shadowright, &m[4]);
4774         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4775         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4776         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4777         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4778         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4779         R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
4780
4781         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4782
4783         R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4784         R_SetupShader_DepthOrShadow();
4785         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4786         GL_DepthMask(true);
4787         GL_DepthTest(true);
4788         R_SetViewport(&viewport);
4789         GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4790         Vector4Set(clearcolor, 1,1,1,1);
4791         // in D3D9 we have to render to a color texture shadowmap
4792         // in GL we render directly to a depth texture only
4793         if (r_shadow_shadowmap2dtexture)
4794                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4795         else
4796                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4797         // render into a slightly restricted region so that the borders of the
4798         // shadowmap area fade away, rather than streaking across everything
4799         // outside the usable area
4800         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4801
4802 #if 0
4803         // debugging
4804         R_Mesh_ResetRenderTargets();
4805         R_SetupShader_ShowDepth();
4806         GL_ColorMask(1,1,1,1);
4807         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4808 #endif
4809
4810         for (i = 0;i < r_refdef.scene.numentities;i++)
4811         {
4812                 ent = r_refdef.scene.entities[i];
4813
4814                 // cast shadows from anything of the map (submodels are optional)
4815                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4816                 {
4817                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4818                         Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4819                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4820                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4821                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4822                         relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4823                         relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4824                         relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4825                         relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4826                         relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4827                         relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4828                         RSurf_ActiveModelEntity(ent, false, false, false);
4829                         ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4830                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4831                 }
4832         }
4833
4834 #if 0
4835         if (r_test.integer)
4836         {
4837                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4838                 CHECKGLERROR
4839                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4840                 CHECKGLERROR
4841                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4842                 Cvar_SetValueQuick(&r_test, 0);
4843                 Z_Free(rawpixels);
4844         }
4845 #endif
4846
4847         R_Shadow_RenderMode_End();
4848
4849         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4850         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4851         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
4852         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4853         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4854         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4855
4856         switch (vid.renderpath)
4857         {
4858         case RENDERPATH_GL11:
4859         case RENDERPATH_GL13:
4860         case RENDERPATH_GL20:
4861         case RENDERPATH_SOFT:
4862         case RENDERPATH_GLES2:
4863                 break;
4864         case RENDERPATH_D3D9:
4865         case RENDERPATH_D3D10:
4866         case RENDERPATH_D3D11:
4867 #ifdef OPENGL_ORIENTATION
4868                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4869                 r_shadow_shadowmapmatrix.m[0][1]        *= -1.0f;
4870                 r_shadow_shadowmapmatrix.m[0][2]        *= -1.0f;
4871                 r_shadow_shadowmapmatrix.m[0][3]        *= -1.0f;
4872 #else
4873                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4874                 r_shadow_shadowmapmatrix.m[1][0]        *= -1.0f;
4875                 r_shadow_shadowmapmatrix.m[2][0]        *= -1.0f;
4876                 r_shadow_shadowmapmatrix.m[3][0]        *= -1.0f;
4877 #endif
4878                 break;
4879         }
4880
4881         r_shadow_usingshadowmaportho = true;
4882         switch (r_shadow_shadowmode)
4883         {
4884         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4885                 r_shadow_usingshadowmap2d = true;
4886                 break;
4887         default:
4888                 break;
4889         }
4890 }
4891
4892 void R_DrawModelShadows(void)
4893 {
4894         int i;
4895         float relativethrowdistance;
4896         entity_render_t *ent;
4897         vec3_t relativelightorigin;
4898         vec3_t relativelightdirection;
4899         vec3_t relativeshadowmins, relativeshadowmaxs;
4900         vec3_t tmp, shadowdir;
4901
4902         if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4903                 return;
4904
4905         R_ResetViewRendering3D();
4906         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4907         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4908         R_Shadow_RenderMode_Begin();
4909         R_Shadow_RenderMode_ActiveLight(NULL);
4910         r_shadow_lightscissor[0] = r_refdef.view.x;
4911         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4912         r_shadow_lightscissor[2] = r_refdef.view.width;
4913         r_shadow_lightscissor[3] = r_refdef.view.height;
4914         R_Shadow_RenderMode_StencilShadowVolumes(false);
4915
4916         // get shadow dir
4917         if (r_shadows.integer == 2)
4918         {
4919                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4920                 VectorNormalize(shadowdir);
4921         }
4922
4923         R_Shadow_ClearStencil();
4924
4925         for (i = 0;i < r_refdef.scene.numentities;i++)
4926         {
4927                 ent = r_refdef.scene.entities[i];
4928
4929                 // cast shadows from anything of the map (submodels are optional)
4930                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4931                 {
4932                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4933                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4934                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4935                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4936                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4937                         else
4938                         {
4939                                 if(ent->entitynumber != 0)
4940                                 {
4941                                         if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4942                                         {
4943                                                 // FIXME handle this
4944                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4945                                         }
4946                                         else
4947                                         {
4948                                                 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4949                                                 int entnum, entnum2, recursion;
4950                                                 entnum = entnum2 = ent->entitynumber;
4951                                                 for(recursion = 32; recursion > 0; --recursion)
4952                                                 {
4953                                                         entnum2 = cl.entities[entnum].state_current.tagentity;
4954                                                         if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4955                                                                 entnum = entnum2;
4956                                                         else
4957                                                                 break;
4958                                                 }
4959                                                 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4960                                                 {
4961                                                         VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4962                                                         // transform into modelspace of OUR entity
4963                                                         Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4964                                                         Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4965                                                 }
4966                                                 else
4967                                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4968                                         }
4969                                 }
4970                                 else
4971                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4972                         }
4973
4974                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4975                         RSurf_ActiveModelEntity(ent, false, false, false);
4976                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4977                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4978                 }
4979         }
4980
4981         // not really the right mode, but this will disable any silly stencil features
4982         R_Shadow_RenderMode_End();
4983
4984         // set up ortho view for rendering this pass
4985         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4986         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4987         //GL_ScissorTest(true);
4988         //R_EntityMatrix(&identitymatrix);
4989         //R_Mesh_ResetTextureState();
4990         R_ResetViewRendering2D();
4991
4992         // set up a darkening blend on shadowed areas
4993         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4994         //GL_DepthRange(0, 1);
4995         //GL_DepthTest(false);
4996         //GL_DepthMask(false);
4997         //GL_PolygonOffset(0, 0);CHECKGLERROR
4998         GL_Color(0, 0, 0, r_shadows_darken.value);
4999         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5000         //GL_DepthFunc(GL_ALWAYS);
5001         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5002
5003         // apply the blend to the shadowed areas
5004         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5005         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5006         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5007
5008         // restore the viewport
5009         R_SetViewport(&r_refdef.view.viewport);
5010
5011         // restore other state to normal
5012         //R_Shadow_RenderMode_End();
5013 }
5014
5015 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5016 {
5017         float zdist;
5018         vec3_t centerorigin;
5019         float vertex3f[12];
5020         // if it's too close, skip it
5021         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5022                 return;
5023         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5024         if (zdist < 32)
5025                 return;
5026         if (usequery && r_numqueries + 2 <= r_maxqueries)
5027         {
5028                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5029                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5030                 // 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
5031                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5032
5033                 switch(vid.renderpath)
5034                 {
5035                 case RENDERPATH_GL20:
5036                 case RENDERPATH_GL13:
5037                 case RENDERPATH_GL11:
5038                 case RENDERPATH_GLES2:
5039                         CHECKGLERROR
5040                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5041                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5042                         GL_DepthFunc(GL_ALWAYS);
5043                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5044                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5045                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5046                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5047                         GL_DepthFunc(GL_LEQUAL);
5048                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5049                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5050                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5051                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5052                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5053                         CHECKGLERROR
5054                         break;
5055                 case RENDERPATH_D3D9:
5056                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5057                         break;
5058                 case RENDERPATH_D3D10:
5059                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5060                         break;
5061                 case RENDERPATH_D3D11:
5062                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5063                         break;
5064                 case RENDERPATH_SOFT:
5065                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5066                         break;
5067                 }
5068         }
5069         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5070 }
5071
5072 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5073
5074 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5075 {
5076         vec3_t color;
5077         GLint allpixels = 0, visiblepixels = 0;
5078         // now we have to check the query result
5079         if (rtlight->corona_queryindex_visiblepixels)
5080         {
5081                 switch(vid.renderpath)
5082                 {
5083                 case RENDERPATH_GL20:
5084                 case RENDERPATH_GL13:
5085                 case RENDERPATH_GL11:
5086                 case RENDERPATH_GLES2:
5087                         CHECKGLERROR
5088                         qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5089                         qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5090                         CHECKGLERROR
5091                         break;
5092                 case RENDERPATH_D3D9:
5093                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5094                         break;
5095                 case RENDERPATH_D3D10:
5096                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5097                         break;
5098                 case RENDERPATH_D3D11:
5099                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5100                         break;
5101                 case RENDERPATH_SOFT:
5102                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5103                         break;
5104                 }
5105                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5106                 if (visiblepixels < 1 || allpixels < 1)
5107                         return;
5108                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5109                 cscale *= rtlight->corona_visibility;
5110         }
5111         else
5112         {
5113                 // FIXME: these traces should scan all render entities instead of cl.world
5114                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
5115                         return;
5116         }
5117         VectorScale(rtlight->currentcolor, cscale, color);
5118         if (VectorLength(color) > (1.0f / 256.0f))
5119         {
5120                 float vertex3f[12];
5121                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5122                 if(negated)
5123                 {
5124                         VectorNegate(color, color);
5125                         switch(vid.renderpath)
5126                         {
5127                         case RENDERPATH_GL11:
5128                         case RENDERPATH_GL13:
5129                         case RENDERPATH_GL20:
5130                         case RENDERPATH_GLES2:
5131                                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
5132                                 break;
5133                         case RENDERPATH_D3D9:
5134 #ifdef SUPPORTD3D
5135                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
5136 #endif
5137                                 break;
5138                         case RENDERPATH_D3D10:
5139                                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5140                                 break;
5141                         case RENDERPATH_D3D11:
5142                                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5143                                 break;
5144                         case RENDERPATH_SOFT:
5145                                 DPSOFTRAST_BlendSubtract(true);
5146                                 break;
5147                         }
5148                 }
5149                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5150                 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);
5151                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5152                 if(negated)
5153                 {
5154                         switch(vid.renderpath)
5155                         {
5156                         case RENDERPATH_GL11:
5157                         case RENDERPATH_GL13:
5158                         case RENDERPATH_GL20:
5159                         case RENDERPATH_GLES2:
5160                                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5161                                 break;
5162                         case RENDERPATH_D3D9:
5163 #ifdef SUPPORTD3D
5164                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5165 #endif
5166                                 break;
5167                         case RENDERPATH_D3D10:
5168                                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5169                                 break;
5170                         case RENDERPATH_D3D11:
5171                                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5172                                 break;
5173                         case RENDERPATH_SOFT:
5174                                 DPSOFTRAST_BlendSubtract(false);
5175                                 break;
5176                         }
5177                 }
5178         }
5179 }
5180
5181 void R_Shadow_DrawCoronas(void)
5182 {
5183         int i, flag;
5184         qboolean usequery = false;
5185         size_t lightindex;
5186         dlight_t *light;
5187         rtlight_t *rtlight;
5188         size_t range;
5189         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5190                 return;
5191         if (r_waterstate.renderingscene)
5192                 return;
5193         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5194         R_EntityMatrix(&identitymatrix);
5195
5196         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5197
5198         // check occlusion of coronas
5199         // use GL_ARB_occlusion_query if available
5200         // otherwise use raytraces
5201         r_numqueries = 0;
5202         switch (vid.renderpath)
5203         {
5204         case RENDERPATH_GL11:
5205         case RENDERPATH_GL13:
5206         case RENDERPATH_GL20:
5207         case RENDERPATH_GLES2:
5208                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5209                 if (usequery)
5210                 {
5211                         GL_ColorMask(0,0,0,0);
5212                         if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5213                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5214                         {
5215                                 i = r_maxqueries;
5216                                 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5217                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5218                                 CHECKGLERROR
5219                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5220                                 CHECKGLERROR
5221                         }
5222                         RSurf_ActiveWorldEntity();
5223                         GL_BlendFunc(GL_ONE, GL_ZERO);
5224                         GL_CullFace(GL_NONE);
5225                         GL_DepthMask(false);
5226                         GL_DepthRange(0, 1);
5227                         GL_PolygonOffset(0, 0);
5228                         GL_DepthTest(true);
5229                         R_Mesh_ResetTextureState();
5230                         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5231                 }
5232                 break;
5233         case RENDERPATH_D3D9:
5234                 usequery = false;
5235                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5236                 break;
5237         case RENDERPATH_D3D10:
5238                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5239                 break;
5240         case RENDERPATH_D3D11:
5241                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5242                 break;
5243         case RENDERPATH_SOFT:
5244                 usequery = false;
5245                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5246                 break;
5247         }
5248         for (lightindex = 0;lightindex < range;lightindex++)
5249         {
5250                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5251                 if (!light)
5252                         continue;
5253                 rtlight = &light->rtlight;
5254                 rtlight->corona_visibility = 0;
5255                 rtlight->corona_queryindex_visiblepixels = 0;
5256                 rtlight->corona_queryindex_allpixels = 0;
5257                 if (!(rtlight->flags & flag))
5258                         continue;
5259                 if (rtlight->corona <= 0)
5260                         continue;
5261                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5262                         continue;
5263                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5264         }
5265         for (i = 0;i < r_refdef.scene.numlights;i++)
5266         {
5267                 rtlight = r_refdef.scene.lights[i];
5268                 rtlight->corona_visibility = 0;
5269                 rtlight->corona_queryindex_visiblepixels = 0;
5270                 rtlight->corona_queryindex_allpixels = 0;
5271                 if (!(rtlight->flags & flag))
5272                         continue;
5273                 if (rtlight->corona <= 0)
5274                         continue;
5275                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5276         }
5277         if (usequery)
5278                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5279
5280         // now draw the coronas using the query data for intensity info
5281         for (lightindex = 0;lightindex < range;lightindex++)
5282         {
5283                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5284                 if (!light)
5285                         continue;
5286                 rtlight = &light->rtlight;
5287                 if (rtlight->corona_visibility <= 0)
5288                         continue;
5289                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5290         }
5291         for (i = 0;i < r_refdef.scene.numlights;i++)
5292         {
5293                 rtlight = r_refdef.scene.lights[i];
5294                 if (rtlight->corona_visibility <= 0)
5295                         continue;
5296                 if (gl_flashblend.integer)
5297                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5298                 else
5299                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5300         }
5301 }
5302
5303
5304
5305 dlight_t *R_Shadow_NewWorldLight(void)
5306 {
5307         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5308 }
5309
5310 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)
5311 {
5312         matrix4x4_t matrix;
5313         // validate parameters
5314         if (style < 0 || style >= MAX_LIGHTSTYLES)
5315         {
5316                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5317                 style = 0;
5318         }
5319         if (!cubemapname)
5320                 cubemapname = "";
5321
5322         // copy to light properties
5323         VectorCopy(origin, light->origin);
5324         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5325         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5326         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5327         /*
5328         light->color[0] = max(color[0], 0);
5329         light->color[1] = max(color[1], 0);
5330         light->color[2] = max(color[2], 0);
5331         */
5332         light->color[0] = color[0];
5333         light->color[1] = color[1];
5334         light->color[2] = color[2];
5335         light->radius = max(radius, 0);
5336         light->style = style;
5337         light->shadow = shadowenable;
5338         light->corona = corona;
5339         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5340         light->coronasizescale = coronasizescale;
5341         light->ambientscale = ambientscale;
5342         light->diffusescale = diffusescale;
5343         light->specularscale = specularscale;
5344         light->flags = flags;
5345
5346         // update renderable light data
5347         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5348         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);
5349 }
5350
5351 void R_Shadow_FreeWorldLight(dlight_t *light)
5352 {
5353         if (r_shadow_selectedlight == light)
5354                 r_shadow_selectedlight = NULL;
5355         R_RTLight_Uncompile(&light->rtlight);
5356         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5357 }
5358
5359 void R_Shadow_ClearWorldLights(void)
5360 {
5361         size_t lightindex;
5362         dlight_t *light;
5363         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5364         for (lightindex = 0;lightindex < range;lightindex++)
5365         {
5366                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5367                 if (light)
5368                         R_Shadow_FreeWorldLight(light);
5369         }
5370         r_shadow_selectedlight = NULL;
5371 }
5372
5373 void R_Shadow_SelectLight(dlight_t *light)
5374 {
5375         if (r_shadow_selectedlight)
5376                 r_shadow_selectedlight->selected = false;
5377         r_shadow_selectedlight = light;
5378         if (r_shadow_selectedlight)
5379                 r_shadow_selectedlight->selected = true;
5380 }
5381
5382 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5383 {
5384         // this is never batched (there can be only one)
5385         float vertex3f[12];
5386         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5387         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5388         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5389 }
5390
5391 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5392 {
5393         float intensity;
5394         float s;
5395         vec3_t spritecolor;
5396         skinframe_t *skinframe;
5397         float vertex3f[12];
5398
5399         // this is never batched (due to the ent parameter changing every time)
5400         // so numsurfaces == 1 and surfacelist[0] == lightnumber
5401         const dlight_t *light = (dlight_t *)ent;
5402         s = EDLIGHTSPRSIZE;
5403
5404         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5405
5406         intensity = 0.5f;
5407         VectorScale(light->color, intensity, spritecolor);
5408         if (VectorLength(spritecolor) < 0.1732f)
5409                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5410         if (VectorLength(spritecolor) > 1.0f)
5411                 VectorNormalize(spritecolor);
5412
5413         // draw light sprite
5414         if (light->cubemapname[0] && !light->shadow)
5415                 skinframe = r_editlights_sprcubemapnoshadowlight;
5416         else if (light->cubemapname[0])
5417                 skinframe = r_editlights_sprcubemaplight;
5418         else if (!light->shadow)
5419                 skinframe = r_editlights_sprnoshadowlight;
5420         else
5421                 skinframe = r_editlights_sprlight;
5422
5423         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);
5424         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5425
5426         // draw selection sprite if light is selected
5427         if (light->selected)
5428         {
5429                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5430                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5431                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5432         }
5433 }
5434
5435 void R_Shadow_DrawLightSprites(void)
5436 {
5437         size_t lightindex;
5438         dlight_t *light;
5439         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5440         for (lightindex = 0;lightindex < range;lightindex++)
5441         {
5442                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5443                 if (light)
5444                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5445         }
5446         if (!r_editlights_lockcursor)
5447                 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5448 }
5449
5450 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5451 {
5452         unsigned int range;
5453         dlight_t *light;
5454         rtlight_t *rtlight;
5455         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5456         if (lightindex >= range)
5457                 return -1;
5458         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5459         if (!light)
5460                 return 0;
5461         rtlight = &light->rtlight;
5462         //if (!(rtlight->flags & flag))
5463         //      return 0;
5464         VectorCopy(rtlight->shadoworigin, origin);
5465         *radius = rtlight->radius;
5466         VectorCopy(rtlight->color, color);
5467         return 1;
5468 }
5469
5470 void R_Shadow_SelectLightInView(void)
5471 {
5472         float bestrating, rating, temp[3];
5473         dlight_t *best;
5474         size_t lightindex;
5475         dlight_t *light;
5476         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5477         best = NULL;
5478         bestrating = 0;
5479
5480         if (r_editlights_lockcursor)
5481                 return;
5482         for (lightindex = 0;lightindex < range;lightindex++)
5483         {
5484                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5485                 if (!light)
5486                         continue;
5487                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5488                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5489                 if (rating >= 0.95)
5490                 {
5491                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5492                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5493                         {
5494                                 bestrating = rating;
5495                                 best = light;
5496                         }
5497                 }
5498         }
5499         R_Shadow_SelectLight(best);
5500 }
5501
5502 void R_Shadow_LoadWorldLights(void)
5503 {
5504         int n, a, style, shadow, flags;
5505         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5506         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5507         if (cl.worldmodel == NULL)
5508         {
5509                 Con_Print("No map loaded.\n");
5510                 return;
5511         }
5512         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5513         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5514         if (lightsstring)
5515         {
5516                 s = lightsstring;
5517                 n = 0;
5518                 while (*s)
5519                 {
5520                         t = s;
5521                         /*
5522                         shadow = true;
5523                         for (;COM_Parse(t, true) && strcmp(
5524                         if (COM_Parse(t, true))
5525                         {
5526                                 if (com_token[0] == '!')
5527                                 {
5528                                         shadow = false;
5529                                         origin[0] = atof(com_token+1);
5530                                 }
5531                                 else
5532                                         origin[0] = atof(com_token);
5533                                 if (Com_Parse(t
5534                         }
5535                         */
5536                         t = s;
5537                         while (*s && *s != '\n' && *s != '\r')
5538                                 s++;
5539                         if (!*s)
5540                                 break;
5541                         tempchar = *s;
5542                         shadow = true;
5543                         // check for modifier flags
5544                         if (*t == '!')
5545                         {
5546                                 shadow = false;
5547                                 t++;
5548                         }
5549                         *s = 0;
5550 #if _MSC_VER >= 1400
5551 #define sscanf sscanf_s
5552 #endif
5553                         cubemapname[sizeof(cubemapname)-1] = 0;
5554 #if MAX_QPATH != 128
5555 #error update this code if MAX_QPATH changes
5556 #endif
5557                         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
5558 #if _MSC_VER >= 1400
5559 , sizeof(cubemapname)
5560 #endif
5561 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5562                         *s = tempchar;
5563                         if (a < 18)
5564                                 flags = LIGHTFLAG_REALTIMEMODE;
5565                         if (a < 17)
5566                                 specularscale = 1;
5567                         if (a < 16)
5568                                 diffusescale = 1;
5569                         if (a < 15)
5570                                 ambientscale = 0;
5571                         if (a < 14)
5572                                 coronasizescale = 0.25f;
5573                         if (a < 13)
5574                                 VectorClear(angles);
5575                         if (a < 10)
5576                                 corona = 0;
5577                         if (a < 9 || !strcmp(cubemapname, "\"\""))
5578                                 cubemapname[0] = 0;
5579                         // remove quotes on cubemapname
5580                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5581                         {
5582                                 size_t namelen;
5583                                 namelen = strlen(cubemapname) - 2;
5584                                 memmove(cubemapname, cubemapname + 1, namelen);
5585                                 cubemapname[namelen] = '\0';
5586                         }
5587                         if (a < 8)
5588                         {
5589                                 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);
5590                                 break;
5591                         }
5592                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5593                         if (*s == '\r')
5594                                 s++;
5595                         if (*s == '\n')
5596                                 s++;
5597                         n++;
5598                 }
5599                 if (*s)
5600                         Con_Printf("invalid rtlights file \"%s\"\n", name);
5601                 Mem_Free(lightsstring);
5602         }
5603 }
5604
5605 void R_Shadow_SaveWorldLights(void)
5606 {
5607         size_t lightindex;
5608         dlight_t *light;
5609         size_t bufchars, bufmaxchars;
5610         char *buf, *oldbuf;
5611         char name[MAX_QPATH];
5612         char line[MAX_INPUTLINE];
5613         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5614         // I hate lines which are 3 times my screen size :( --blub
5615         if (!range)
5616                 return;
5617         if (cl.worldmodel == NULL)
5618         {
5619                 Con_Print("No map loaded.\n");
5620                 return;
5621         }
5622         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5623         bufchars = bufmaxchars = 0;
5624         buf = NULL;
5625         for (lightindex = 0;lightindex < range;lightindex++)
5626         {
5627                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5628                 if (!light)
5629                         continue;
5630                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5631                         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);
5632                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5633                         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]);
5634                 else
5635                         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);
5636                 if (bufchars + strlen(line) > bufmaxchars)
5637                 {
5638                         bufmaxchars = bufchars + strlen(line) + 2048;
5639                         oldbuf = buf;
5640                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5641                         if (oldbuf)
5642                         {
5643                                 if (bufchars)
5644                                         memcpy(buf, oldbuf, bufchars);
5645                                 Mem_Free(oldbuf);
5646                         }
5647                 }
5648                 if (strlen(line))
5649                 {
5650                         memcpy(buf + bufchars, line, strlen(line));
5651                         bufchars += strlen(line);
5652                 }
5653         }
5654         if (bufchars)
5655                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5656         if (buf)
5657                 Mem_Free(buf);
5658 }
5659
5660 void R_Shadow_LoadLightsFile(void)
5661 {
5662         int n, a, style;
5663         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5664         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5665         if (cl.worldmodel == NULL)
5666         {
5667                 Con_Print("No map loaded.\n");
5668                 return;
5669         }
5670         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5671         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5672         if (lightsstring)
5673         {
5674                 s = lightsstring;
5675                 n = 0;
5676                 while (*s)
5677                 {
5678                         t = s;
5679                         while (*s && *s != '\n' && *s != '\r')
5680                                 s++;
5681                         if (!*s)
5682                                 break;
5683                         tempchar = *s;
5684                         *s = 0;
5685                         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);
5686                         *s = tempchar;
5687                         if (a < 14)
5688                         {
5689                                 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);
5690                                 break;
5691                         }
5692                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5693                         radius = bound(15, radius, 4096);
5694                         VectorScale(color, (2.0f / (8388608.0f)), color);
5695                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5696                         if (*s == '\r')
5697                                 s++;
5698                         if (*s == '\n')
5699                                 s++;
5700                         n++;
5701                 }
5702                 if (*s)
5703                         Con_Printf("invalid lights file \"%s\"\n", name);
5704                 Mem_Free(lightsstring);
5705         }
5706 }
5707
5708 // tyrlite/hmap2 light types in the delay field
5709 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5710
5711 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5712 {
5713         int entnum;
5714         int style;
5715         int islight;
5716         int skin;
5717         int pflags;
5718         //int effects;
5719         int type;
5720         int n;
5721         char *entfiledata;
5722         const char *data;
5723         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5724         char key[256], value[MAX_INPUTLINE];
5725
5726         if (cl.worldmodel == NULL)
5727         {
5728                 Con_Print("No map loaded.\n");
5729                 return;
5730         }
5731         // try to load a .ent file first
5732         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5733         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5734         // and if that is not found, fall back to the bsp file entity string
5735         if (!data)
5736                 data = cl.worldmodel->brush.entities;
5737         if (!data)
5738                 return;
5739         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5740         {
5741                 type = LIGHTTYPE_MINUSX;
5742                 origin[0] = origin[1] = origin[2] = 0;
5743                 originhack[0] = originhack[1] = originhack[2] = 0;
5744                 angles[0] = angles[1] = angles[2] = 0;
5745                 color[0] = color[1] = color[2] = 1;
5746                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5747                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5748                 fadescale = 1;
5749                 lightscale = 1;
5750                 style = 0;
5751                 skin = 0;
5752                 pflags = 0;
5753                 //effects = 0;
5754                 islight = false;
5755                 while (1)
5756                 {
5757                         if (!COM_ParseToken_Simple(&data, false, false))
5758                                 break; // error
5759                         if (com_token[0] == '}')
5760                                 break; // end of entity
5761                         if (com_token[0] == '_')
5762                                 strlcpy(key, com_token + 1, sizeof(key));
5763                         else
5764                                 strlcpy(key, com_token, sizeof(key));
5765                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5766                                 key[strlen(key)-1] = 0;
5767                         if (!COM_ParseToken_Simple(&data, false, false))
5768                                 break; // error
5769                         strlcpy(value, com_token, sizeof(value));
5770
5771                         // now that we have the key pair worked out...
5772                         if (!strcmp("light", key))
5773                         {
5774                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5775                                 if (n == 1)
5776                                 {
5777                                         // quake
5778                                         light[0] = vec[0] * (1.0f / 256.0f);
5779                                         light[1] = vec[0] * (1.0f / 256.0f);
5780                                         light[2] = vec[0] * (1.0f / 256.0f);
5781                                         light[3] = vec[0];
5782                                 }
5783                                 else if (n == 4)
5784                                 {
5785                                         // halflife
5786                                         light[0] = vec[0] * (1.0f / 255.0f);
5787                                         light[1] = vec[1] * (1.0f / 255.0f);
5788                                         light[2] = vec[2] * (1.0f / 255.0f);
5789                                         light[3] = vec[3];
5790                                 }
5791                         }
5792                         else if (!strcmp("delay", key))
5793                                 type = atoi(value);
5794                         else if (!strcmp("origin", key))
5795                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5796                         else if (!strcmp("angle", key))
5797                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5798                         else if (!strcmp("angles", key))
5799                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5800                         else if (!strcmp("color", key))
5801                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5802                         else if (!strcmp("wait", key))
5803                                 fadescale = atof(value);
5804                         else if (!strcmp("classname", key))
5805                         {
5806                                 if (!strncmp(value, "light", 5))
5807                                 {
5808                                         islight = true;
5809                                         if (!strcmp(value, "light_fluoro"))
5810                                         {
5811                                                 originhack[0] = 0;
5812                                                 originhack[1] = 0;
5813                                                 originhack[2] = 0;
5814                                                 overridecolor[0] = 1;
5815                                                 overridecolor[1] = 1;
5816                                                 overridecolor[2] = 1;
5817                                         }
5818                                         if (!strcmp(value, "light_fluorospark"))
5819                                         {
5820                                                 originhack[0] = 0;
5821                                                 originhack[1] = 0;
5822                                                 originhack[2] = 0;
5823                                                 overridecolor[0] = 1;
5824                                                 overridecolor[1] = 1;
5825                                                 overridecolor[2] = 1;
5826                                         }
5827                                         if (!strcmp(value, "light_globe"))
5828                                         {
5829                                                 originhack[0] = 0;
5830                                                 originhack[1] = 0;
5831                                                 originhack[2] = 0;
5832                                                 overridecolor[0] = 1;
5833                                                 overridecolor[1] = 0.8;
5834                                                 overridecolor[2] = 0.4;
5835                                         }
5836                                         if (!strcmp(value, "light_flame_large_yellow"))
5837                                         {
5838                                                 originhack[0] = 0;
5839                                                 originhack[1] = 0;
5840                                                 originhack[2] = 0;
5841                                                 overridecolor[0] = 1;
5842                                                 overridecolor[1] = 0.5;
5843                                                 overridecolor[2] = 0.1;
5844                                         }
5845                                         if (!strcmp(value, "light_flame_small_yellow"))
5846                                         {
5847                                                 originhack[0] = 0;
5848                                                 originhack[1] = 0;
5849                                                 originhack[2] = 0;
5850                                                 overridecolor[0] = 1;
5851                                                 overridecolor[1] = 0.5;
5852                                                 overridecolor[2] = 0.1;
5853                                         }
5854                                         if (!strcmp(value, "light_torch_small_white"))
5855                                         {
5856                                                 originhack[0] = 0;
5857                                                 originhack[1] = 0;
5858                                                 originhack[2] = 0;
5859                                                 overridecolor[0] = 1;
5860                                                 overridecolor[1] = 0.5;
5861                                                 overridecolor[2] = 0.1;
5862                                         }
5863                                         if (!strcmp(value, "light_torch_small_walltorch"))
5864                                         {
5865                                                 originhack[0] = 0;
5866                                                 originhack[1] = 0;
5867                                                 originhack[2] = 0;
5868                                                 overridecolor[0] = 1;
5869                                                 overridecolor[1] = 0.5;
5870                                                 overridecolor[2] = 0.1;
5871                                         }
5872                                 }
5873                         }
5874                         else if (!strcmp("style", key))
5875                                 style = atoi(value);
5876                         else if (!strcmp("skin", key))
5877                                 skin = (int)atof(value);
5878                         else if (!strcmp("pflags", key))
5879                                 pflags = (int)atof(value);
5880                         //else if (!strcmp("effects", key))
5881                         //      effects = (int)atof(value);
5882                         else if (cl.worldmodel->type == mod_brushq3)
5883                         {
5884                                 if (!strcmp("scale", key))
5885                                         lightscale = atof(value);
5886                                 if (!strcmp("fade", key))
5887                                         fadescale = atof(value);
5888                         }
5889                 }
5890                 if (!islight)
5891                         continue;
5892                 if (lightscale <= 0)
5893                         lightscale = 1;
5894                 if (fadescale <= 0)
5895                         fadescale = 1;
5896                 if (color[0] == color[1] && color[0] == color[2])
5897                 {
5898                         color[0] *= overridecolor[0];
5899                         color[1] *= overridecolor[1];
5900                         color[2] *= overridecolor[2];
5901                 }
5902                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5903                 color[0] = color[0] * light[0];
5904                 color[1] = color[1] * light[1];
5905                 color[2] = color[2] * light[2];
5906                 switch (type)
5907                 {
5908                 case LIGHTTYPE_MINUSX:
5909                         break;
5910                 case LIGHTTYPE_RECIPX:
5911                         radius *= 2;
5912                         VectorScale(color, (1.0f / 16.0f), color);
5913                         break;
5914                 case LIGHTTYPE_RECIPXX:
5915                         radius *= 2;
5916                         VectorScale(color, (1.0f / 16.0f), color);
5917                         break;
5918                 default:
5919                 case LIGHTTYPE_NONE:
5920                         break;
5921                 case LIGHTTYPE_SUN:
5922                         break;
5923                 case LIGHTTYPE_MINUSXX:
5924                         break;
5925                 }
5926                 VectorAdd(origin, originhack, origin);
5927                 if (radius >= 1)
5928                         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);
5929         }
5930         if (entfiledata)
5931                 Mem_Free(entfiledata);
5932 }
5933
5934
5935 void R_Shadow_SetCursorLocationForView(void)
5936 {
5937         vec_t dist, push;
5938         vec3_t dest, endpos;
5939         trace_t trace;
5940         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5941         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5942         if (trace.fraction < 1)
5943         {
5944                 dist = trace.fraction * r_editlights_cursordistance.value;
5945                 push = r_editlights_cursorpushback.value;
5946                 if (push > dist)
5947                         push = dist;
5948                 push = -push;
5949                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5950                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5951         }
5952         else
5953         {
5954                 VectorClear( endpos );
5955         }
5956         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5957         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5958         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5959 }
5960
5961 void R_Shadow_UpdateWorldLightSelection(void)
5962 {
5963         if (r_editlights.integer)
5964         {
5965                 R_Shadow_SetCursorLocationForView();
5966                 R_Shadow_SelectLightInView();
5967         }
5968         else
5969                 R_Shadow_SelectLight(NULL);
5970 }
5971
5972 void R_Shadow_EditLights_Clear_f(void)
5973 {
5974         R_Shadow_ClearWorldLights();
5975 }
5976
5977 void R_Shadow_EditLights_Reload_f(void)
5978 {
5979         if (!cl.worldmodel)
5980                 return;
5981         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5982         R_Shadow_ClearWorldLights();
5983         R_Shadow_LoadWorldLights();
5984         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5985         {
5986                 R_Shadow_LoadLightsFile();
5987                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5988                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5989         }
5990 }
5991
5992 void R_Shadow_EditLights_Save_f(void)
5993 {
5994         if (!cl.worldmodel)
5995                 return;
5996         R_Shadow_SaveWorldLights();
5997 }
5998
5999 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6000 {
6001         R_Shadow_ClearWorldLights();
6002         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6003 }
6004
6005 void R_Shadow_EditLights_ImportLightsFile_f(void)
6006 {
6007         R_Shadow_ClearWorldLights();
6008         R_Shadow_LoadLightsFile();
6009 }
6010
6011 void R_Shadow_EditLights_Spawn_f(void)
6012 {
6013         vec3_t color;
6014         if (!r_editlights.integer)
6015         {
6016                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6017                 return;
6018         }
6019         if (Cmd_Argc() != 1)
6020         {
6021                 Con_Print("r_editlights_spawn does not take parameters\n");
6022                 return;
6023         }
6024         color[0] = color[1] = color[2] = 1;
6025         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6026 }
6027
6028 void R_Shadow_EditLights_Edit_f(void)
6029 {
6030         vec3_t origin, angles, color;
6031         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6032         int style, shadows, flags, normalmode, realtimemode;
6033         char cubemapname[MAX_INPUTLINE];
6034         if (!r_editlights.integer)
6035         {
6036                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6037                 return;
6038         }
6039         if (!r_shadow_selectedlight)
6040         {
6041                 Con_Print("No selected light.\n");
6042                 return;
6043         }
6044         VectorCopy(r_shadow_selectedlight->origin, origin);
6045         VectorCopy(r_shadow_selectedlight->angles, angles);
6046         VectorCopy(r_shadow_selectedlight->color, color);
6047         radius = r_shadow_selectedlight->radius;
6048         style = r_shadow_selectedlight->style;
6049         if (r_shadow_selectedlight->cubemapname)
6050                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6051         else
6052                 cubemapname[0] = 0;
6053         shadows = r_shadow_selectedlight->shadow;
6054         corona = r_shadow_selectedlight->corona;
6055         coronasizescale = r_shadow_selectedlight->coronasizescale;
6056         ambientscale = r_shadow_selectedlight->ambientscale;
6057         diffusescale = r_shadow_selectedlight->diffusescale;
6058         specularscale = r_shadow_selectedlight->specularscale;
6059         flags = r_shadow_selectedlight->flags;
6060         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6061         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6062         if (!strcmp(Cmd_Argv(1), "origin"))
6063         {
6064                 if (Cmd_Argc() != 5)
6065                 {
6066                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6067                         return;
6068                 }
6069                 origin[0] = atof(Cmd_Argv(2));
6070                 origin[1] = atof(Cmd_Argv(3));
6071                 origin[2] = atof(Cmd_Argv(4));
6072         }
6073         else if (!strcmp(Cmd_Argv(1), "originx"))
6074         {
6075                 if (Cmd_Argc() != 3)
6076                 {
6077                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6078                         return;
6079                 }
6080                 origin[0] = atof(Cmd_Argv(2));
6081         }
6082         else if (!strcmp(Cmd_Argv(1), "originy"))
6083         {
6084                 if (Cmd_Argc() != 3)
6085                 {
6086                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6087                         return;
6088                 }
6089                 origin[1] = atof(Cmd_Argv(2));
6090         }
6091         else if (!strcmp(Cmd_Argv(1), "originz"))
6092         {
6093                 if (Cmd_Argc() != 3)
6094                 {
6095                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6096                         return;
6097                 }
6098                 origin[2] = atof(Cmd_Argv(2));
6099         }
6100         else if (!strcmp(Cmd_Argv(1), "move"))
6101         {
6102                 if (Cmd_Argc() != 5)
6103                 {
6104                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6105                         return;
6106                 }
6107                 origin[0] += atof(Cmd_Argv(2));
6108                 origin[1] += atof(Cmd_Argv(3));
6109                 origin[2] += atof(Cmd_Argv(4));
6110         }
6111         else if (!strcmp(Cmd_Argv(1), "movex"))
6112         {
6113                 if (Cmd_Argc() != 3)
6114                 {
6115                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6116                         return;
6117                 }
6118                 origin[0] += atof(Cmd_Argv(2));
6119         }
6120         else if (!strcmp(Cmd_Argv(1), "movey"))
6121         {
6122                 if (Cmd_Argc() != 3)
6123                 {
6124                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6125                         return;
6126                 }
6127                 origin[1] += atof(Cmd_Argv(2));
6128         }
6129         else if (!strcmp(Cmd_Argv(1), "movez"))
6130         {
6131                 if (Cmd_Argc() != 3)
6132                 {
6133                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6134                         return;
6135                 }
6136                 origin[2] += atof(Cmd_Argv(2));
6137         }
6138         else if (!strcmp(Cmd_Argv(1), "angles"))
6139         {
6140                 if (Cmd_Argc() != 5)
6141                 {
6142                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6143                         return;
6144                 }
6145                 angles[0] = atof(Cmd_Argv(2));
6146                 angles[1] = atof(Cmd_Argv(3));
6147                 angles[2] = atof(Cmd_Argv(4));
6148         }
6149         else if (!strcmp(Cmd_Argv(1), "anglesx"))
6150         {
6151                 if (Cmd_Argc() != 3)
6152                 {
6153                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6154                         return;
6155                 }
6156                 angles[0] = atof(Cmd_Argv(2));
6157         }
6158         else if (!strcmp(Cmd_Argv(1), "anglesy"))
6159         {
6160                 if (Cmd_Argc() != 3)
6161                 {
6162                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6163                         return;
6164                 }
6165                 angles[1] = atof(Cmd_Argv(2));
6166         }
6167         else if (!strcmp(Cmd_Argv(1), "anglesz"))
6168         {
6169                 if (Cmd_Argc() != 3)
6170                 {
6171                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6172                         return;
6173                 }
6174                 angles[2] = atof(Cmd_Argv(2));
6175         }
6176         else if (!strcmp(Cmd_Argv(1), "color"))
6177         {
6178                 if (Cmd_Argc() != 5)
6179                 {
6180                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6181                         return;
6182                 }
6183                 color[0] = atof(Cmd_Argv(2));
6184                 color[1] = atof(Cmd_Argv(3));
6185                 color[2] = atof(Cmd_Argv(4));
6186         }
6187         else if (!strcmp(Cmd_Argv(1), "radius"))
6188         {
6189                 if (Cmd_Argc() != 3)
6190                 {
6191                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6192                         return;
6193                 }
6194                 radius = atof(Cmd_Argv(2));
6195         }
6196         else if (!strcmp(Cmd_Argv(1), "colorscale"))
6197         {
6198                 if (Cmd_Argc() == 3)
6199                 {
6200                         double scale = atof(Cmd_Argv(2));
6201                         color[0] *= scale;
6202                         color[1] *= scale;
6203                         color[2] *= scale;
6204                 }
6205                 else
6206                 {
6207                         if (Cmd_Argc() != 5)
6208                         {
6209                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
6210                                 return;
6211                         }
6212                         color[0] *= atof(Cmd_Argv(2));
6213                         color[1] *= atof(Cmd_Argv(3));
6214                         color[2] *= atof(Cmd_Argv(4));
6215                 }
6216         }
6217         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6218         {
6219                 if (Cmd_Argc() != 3)
6220                 {
6221                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6222                         return;
6223                 }
6224                 radius *= atof(Cmd_Argv(2));
6225         }
6226         else if (!strcmp(Cmd_Argv(1), "style"))
6227         {
6228                 if (Cmd_Argc() != 3)
6229                 {
6230                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6231                         return;
6232                 }
6233                 style = atoi(Cmd_Argv(2));
6234         }
6235         else if (!strcmp(Cmd_Argv(1), "cubemap"))
6236         {
6237                 if (Cmd_Argc() > 3)
6238                 {
6239                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6240                         return;
6241                 }
6242                 if (Cmd_Argc() == 3)
6243                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6244                 else
6245                         cubemapname[0] = 0;
6246         }
6247         else if (!strcmp(Cmd_Argv(1), "shadows"))
6248         {
6249                 if (Cmd_Argc() != 3)
6250                 {
6251                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6252                         return;
6253                 }
6254                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6255         }
6256         else if (!strcmp(Cmd_Argv(1), "corona"))
6257         {
6258                 if (Cmd_Argc() != 3)
6259                 {
6260                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6261                         return;
6262                 }
6263                 corona = atof(Cmd_Argv(2));
6264         }
6265         else if (!strcmp(Cmd_Argv(1), "coronasize"))
6266         {
6267                 if (Cmd_Argc() != 3)
6268                 {
6269                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6270                         return;
6271                 }
6272                 coronasizescale = atof(Cmd_Argv(2));
6273         }
6274         else if (!strcmp(Cmd_Argv(1), "ambient"))
6275         {
6276                 if (Cmd_Argc() != 3)
6277                 {
6278                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6279                         return;
6280                 }
6281                 ambientscale = atof(Cmd_Argv(2));
6282         }
6283         else if (!strcmp(Cmd_Argv(1), "diffuse"))
6284         {
6285                 if (Cmd_Argc() != 3)
6286                 {
6287                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6288                         return;
6289                 }
6290                 diffusescale = atof(Cmd_Argv(2));
6291         }
6292         else if (!strcmp(Cmd_Argv(1), "specular"))
6293         {
6294                 if (Cmd_Argc() != 3)
6295                 {
6296                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6297                         return;
6298                 }
6299                 specularscale = atof(Cmd_Argv(2));
6300         }
6301         else if (!strcmp(Cmd_Argv(1), "normalmode"))
6302         {
6303                 if (Cmd_Argc() != 3)
6304                 {
6305                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6306                         return;
6307                 }
6308                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6309         }
6310         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6311         {
6312                 if (Cmd_Argc() != 3)
6313                 {
6314                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6315                         return;
6316                 }
6317                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6318         }
6319         else
6320         {
6321                 Con_Print("usage: r_editlights_edit [property] [value]\n");
6322                 Con_Print("Selected light's properties:\n");
6323                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6324                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6325                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6326                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
6327                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
6328                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
6329                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6330                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
6331                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
6332                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
6333                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
6334                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
6335                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6336                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6337                 return;
6338         }
6339         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6340         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6341 }
6342
6343 void R_Shadow_EditLights_EditAll_f(void)
6344 {
6345         size_t lightindex;
6346         dlight_t *light, *oldselected;
6347         size_t range;
6348
6349         if (!r_editlights.integer)
6350         {
6351                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6352                 return;
6353         }
6354
6355         oldselected = r_shadow_selectedlight;
6356         // EditLights doesn't seem to have a "remove" command or something so:
6357         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6358         for (lightindex = 0;lightindex < range;lightindex++)
6359         {
6360                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6361                 if (!light)
6362                         continue;
6363                 R_Shadow_SelectLight(light);
6364                 R_Shadow_EditLights_Edit_f();
6365         }
6366         // return to old selected (to not mess editing once selection is locked)
6367         R_Shadow_SelectLight(oldselected);
6368 }
6369
6370 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6371 {
6372         int lightnumber, lightcount;
6373         size_t lightindex, range;
6374         dlight_t *light;
6375         float x, y;
6376         char temp[256];
6377         if (!r_editlights.integer)
6378                 return;
6379         x = vid_conwidth.value - 240;
6380         y = 5;
6381         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6382         lightnumber = -1;
6383         lightcount = 0;
6384         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6385         for (lightindex = 0;lightindex < range;lightindex++)
6386         {
6387                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6388                 if (!light)
6389                         continue;
6390                 if (light == r_shadow_selectedlight)
6391                         lightnumber = lightindex;
6392                 lightcount++;
6393         }
6394         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;
6395         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;
6396         y += 8;
6397         if (r_shadow_selectedlight == NULL)
6398                 return;
6399         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;
6400         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;
6401         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;
6402         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;
6403         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;
6404         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;
6405         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;
6406         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;
6407         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;
6408         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;
6409         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;
6410         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;
6411         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;
6412         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;
6413         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;
6414 }
6415
6416 void R_Shadow_EditLights_ToggleShadow_f(void)
6417 {
6418         if (!r_editlights.integer)
6419         {
6420                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6421                 return;
6422         }
6423         if (!r_shadow_selectedlight)
6424         {
6425                 Con_Print("No selected light.\n");
6426                 return;
6427         }
6428         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);
6429 }
6430
6431 void R_Shadow_EditLights_ToggleCorona_f(void)
6432 {
6433         if (!r_editlights.integer)
6434         {
6435                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6436                 return;
6437         }
6438         if (!r_shadow_selectedlight)
6439         {
6440                 Con_Print("No selected light.\n");
6441                 return;
6442         }
6443         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);
6444 }
6445
6446 void R_Shadow_EditLights_Remove_f(void)
6447 {
6448         if (!r_editlights.integer)
6449         {
6450                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
6451                 return;
6452         }
6453         if (!r_shadow_selectedlight)
6454         {
6455                 Con_Print("No selected light.\n");
6456                 return;
6457         }
6458         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6459         r_shadow_selectedlight = NULL;
6460 }
6461
6462 void R_Shadow_EditLights_Help_f(void)
6463 {
6464         Con_Print(
6465 "Documentation on r_editlights system:\n"
6466 "Settings:\n"
6467 "r_editlights : enable/disable editing mode\n"
6468 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6469 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6470 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6471 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6472 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6473 "Commands:\n"
6474 "r_editlights_help : this help\n"
6475 "r_editlights_clear : remove all lights\n"
6476 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6477 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6478 "r_editlights_save : save to .rtlights file\n"
6479 "r_editlights_spawn : create a light with default settings\n"
6480 "r_editlights_edit command : edit selected light - more documentation below\n"
6481 "r_editlights_remove : remove selected light\n"
6482 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6483 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6484 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6485 "Edit commands:\n"
6486 "origin x y z : set light location\n"
6487 "originx x: set x component of light location\n"
6488 "originy y: set y component of light location\n"
6489 "originz z: set z component of light location\n"
6490 "move x y z : adjust light location\n"
6491 "movex x: adjust x component of light location\n"
6492 "movey y: adjust y component of light location\n"
6493 "movez z: adjust z component of light location\n"
6494 "angles x y z : set light angles\n"
6495 "anglesx x: set x component of light angles\n"
6496 "anglesy y: set y component of light angles\n"
6497 "anglesz z: set z component of light angles\n"
6498 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6499 "radius radius : set radius (size) of light\n"
6500 "colorscale grey : multiply color of light (1 does nothing)\n"
6501 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6502 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6503 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6504 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6505 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6506 "shadows 1/0 : turn on/off shadows\n"
6507 "corona n : set corona intensity\n"
6508 "coronasize n : set corona size (0-1)\n"
6509 "ambient n : set ambient intensity (0-1)\n"
6510 "diffuse n : set diffuse intensity (0-1)\n"
6511 "specular n : set specular intensity (0-1)\n"
6512 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6513 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6514 "<nothing> : print light properties to console\n"
6515         );
6516 }
6517
6518 void R_Shadow_EditLights_CopyInfo_f(void)
6519 {
6520         if (!r_editlights.integer)
6521         {
6522                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
6523                 return;
6524         }
6525         if (!r_shadow_selectedlight)
6526         {
6527                 Con_Print("No selected light.\n");
6528                 return;
6529         }
6530         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6531         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6532         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6533         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6534         if (r_shadow_selectedlight->cubemapname)
6535                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6536         else
6537                 r_shadow_bufferlight.cubemapname[0] = 0;
6538         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6539         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6540         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6541         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6542         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6543         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6544         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6545 }
6546
6547 void R_Shadow_EditLights_PasteInfo_f(void)
6548 {
6549         if (!r_editlights.integer)
6550         {
6551                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
6552                 return;
6553         }
6554         if (!r_shadow_selectedlight)
6555         {
6556                 Con_Print("No selected light.\n");
6557                 return;
6558         }
6559         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);
6560 }
6561
6562 void R_Shadow_EditLights_Lock_f(void)
6563 {
6564         if (!r_editlights.integer)
6565         {
6566                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
6567                 return;
6568         }
6569         if (r_editlights_lockcursor)
6570         {
6571                 r_editlights_lockcursor = false;
6572                 return;
6573         }
6574         if (!r_shadow_selectedlight)
6575         {
6576                 Con_Print("No selected light to lock on.\n");
6577                 return;
6578         }
6579         r_editlights_lockcursor = true;
6580 }
6581
6582 void R_Shadow_EditLights_Init(void)
6583 {
6584         Cvar_RegisterVariable(&r_editlights);
6585         Cvar_RegisterVariable(&r_editlights_cursordistance);
6586         Cvar_RegisterVariable(&r_editlights_cursorpushback);
6587         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6588         Cvar_RegisterVariable(&r_editlights_cursorgrid);
6589         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6590         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6591         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6592         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)");
6593         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6594         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6595         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6596         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)");
6597         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6598         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6599         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6600         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6601         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6602         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6603         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)");
6604         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6605 }
6606
6607
6608
6609 /*
6610 =============================================================================
6611
6612 LIGHT SAMPLING
6613
6614 =============================================================================
6615 */
6616
6617 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6618 {
6619         int i, numlights, flag;
6620         rtlight_t *light;
6621         dlight_t *dlight;
6622         float relativepoint[3];
6623         float color[3];
6624         float dir[3];
6625         float dist;
6626         float dist2;
6627         float intensity;
6628         float sample[5*3];
6629         float lightradius2;
6630
6631         if (r_fullbright.integer)
6632         {
6633                 VectorSet(ambient, 1, 1, 1);
6634                 VectorClear(diffuse);
6635                 VectorClear(lightdir);
6636                 return;
6637         }
6638
6639         if (flags & LP_LIGHTMAP)
6640         {
6641                 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6642                 VectorClear(diffuse);
6643                 VectorClear(lightdir);
6644                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6645                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6646                 return;
6647         }
6648
6649         memset(sample, 0, sizeof(sample));
6650         VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6651
6652         if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6653         {
6654                 vec3_t tempambient;
6655                 VectorClear(tempambient);
6656                 VectorClear(color);
6657                 VectorClear(relativepoint);
6658                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6659                 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6660                 VectorScale(color, r_refdef.lightmapintensity, color);
6661                 VectorAdd(sample, tempambient, sample);
6662                 VectorMA(sample    , 0.5f            , color, sample    );
6663                 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6664                 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6665                 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6666                 // calculate a weighted average light direction as well
6667                 intensity = VectorLength(color);
6668                 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6669         }
6670
6671         if (flags & LP_RTWORLD)
6672         {
6673                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6674                 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6675                 for (i = 0; i < numlights; i++)
6676                 {
6677                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6678                         if (!dlight)
6679                                 continue;
6680                         light = &dlight->rtlight;
6681                         if (!(light->flags & flag))
6682                                 continue;
6683                         // sample
6684                         lightradius2 = light->radius * light->radius;
6685                         VectorSubtract(light->shadoworigin, p, relativepoint);
6686                         dist2 = VectorLength2(relativepoint);
6687                         if (dist2 >= lightradius2)
6688                                 continue;
6689                         dist = sqrt(dist2) / light->radius;
6690                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6691                         if (intensity <= 0.0f)
6692                                 continue;
6693                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6694                                 continue;
6695                         // scale down intensity to add to both ambient and diffuse
6696                         //intensity *= 0.5f;
6697                         VectorNormalize(relativepoint);
6698                         VectorScale(light->currentcolor, intensity, color);
6699                         VectorMA(sample    , 0.5f            , color, sample    );
6700                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6701                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6702                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6703                         // calculate a weighted average light direction as well
6704                         intensity *= VectorLength(color);
6705                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6706                 }
6707         }
6708
6709         if (flags & LP_DYNLIGHT)
6710         {
6711                 // sample dlights
6712                 for (i = 0;i < r_refdef.scene.numlights;i++)
6713                 {
6714                         light = r_refdef.scene.lights[i];
6715                         // sample
6716                         lightradius2 = light->radius * light->radius;
6717                         VectorSubtract(light->shadoworigin, p, relativepoint);
6718                         dist2 = VectorLength2(relativepoint);
6719                         if (dist2 >= lightradius2)
6720                                 continue;
6721                         dist = sqrt(dist2) / light->radius;
6722                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6723                         if (intensity <= 0.0f)
6724                                 continue;
6725                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6726                                 continue;
6727                         // scale down intensity to add to both ambient and diffuse
6728                         //intensity *= 0.5f;
6729                         VectorNormalize(relativepoint);
6730                         VectorScale(light->currentcolor, intensity, color);
6731                         VectorMA(sample    , 0.5f            , color, sample    );
6732                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6733                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6734                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6735                         // calculate a weighted average light direction as well
6736                         intensity *= VectorLength(color);
6737                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6738                 }
6739         }
6740
6741         // calculate the direction we'll use to reduce the sample to a directional light source
6742         VectorCopy(sample + 12, dir);
6743         //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6744         VectorNormalize(dir);
6745         // extract the diffuse color along the chosen direction and scale it
6746         diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6747         diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6748         diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6749         // subtract some of diffuse from ambient
6750         VectorMA(sample, -0.333f, diffuse, ambient);
6751         // store the normalized lightdir
6752         VectorCopy(dir, lightdir);
6753 }