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