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