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