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