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