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