]> icculus.org git repositories - divverent/darkplaces.git/blob - r_shadow.c
only issue one clear for 2D/rect shadowmaps
[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(~0);CHECKGLERROR
1964         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1965         qglStencilFunc(GL_ALWAYS, 128, ~0);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(~0);CHECKGLERROR
2018                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2019                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2020                 qglStencilMask(~0);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(~0);CHECKGLERROR
2028                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2029                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2030                 qglStencilMask(~0);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_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_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_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_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, ~0);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, ~0);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, ~0);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.support.arb_texture_rectangle || 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_LoadTextureShadowMapRectangle(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4046                         r_shadow_prepassgeometrynormalmaptexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4047                         r_shadow_prepasslightingdiffusetexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4048                         r_shadow_prepasslightingspeculartexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_BGRA, 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_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4054                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4055                         // render depth into one texture and normalmap into the other
4056                         qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4057                         qglReadBuffer(GL_NONE);CHECKGLERROR
4058                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4059                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4060                         {
4061                                 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4062                                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4063                                 r_shadow_usingdeferredprepass = false;
4064                         }
4065
4066                         // set up the lighting pass fbo (diffuse + specular)
4067                         qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4068                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4069                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4070                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4071                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4072                         // render diffuse into one texture and specular into another,
4073                         // with depth and normalmap bound as textures,
4074                         // with depth bound as attachment as well
4075                         qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4076                         qglReadBuffer(GL_NONE);CHECKGLERROR
4077                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4078                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4079                         {
4080                                 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4081                                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4082                                 r_shadow_usingdeferredprepass = false;
4083                         }
4084                 }
4085                 break;
4086         case RENDERPATH_GL13:
4087         case RENDERPATH_GL11:
4088                 r_shadow_usingdeferredprepass = false;
4089                 break;
4090         }
4091
4092         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);
4093
4094         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4095         if (r_shadow_debuglight.integer >= 0)
4096         {
4097                 lightindex = r_shadow_debuglight.integer;
4098                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4099                 if (light && (light->flags & flag))
4100                         R_Shadow_PrepareLight(&light->rtlight);
4101         }
4102         else
4103         {
4104                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4105                 for (lightindex = 0;lightindex < range;lightindex++)
4106                 {
4107                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4108                         if (light && (light->flags & flag))
4109                                 R_Shadow_PrepareLight(&light->rtlight);
4110                 }
4111         }
4112         if (r_refdef.scene.rtdlight)
4113         {
4114                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4115                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4116         }
4117         else if(gl_flashblend.integer)
4118         {
4119                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4120                 {
4121                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4122                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4123                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4124                 }
4125         }
4126
4127         if (r_editlights.integer)
4128                 R_Shadow_DrawLightSprites();
4129 }
4130
4131 void R_Shadow_DrawLights(void)
4132 {
4133         int flag;
4134         int lnum;
4135         size_t lightindex;
4136         dlight_t *light;
4137         size_t range;
4138
4139         R_Shadow_RenderMode_Begin();
4140
4141         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4142         if (r_shadow_debuglight.integer >= 0)
4143         {
4144                 lightindex = r_shadow_debuglight.integer;
4145                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4146                 if (light && (light->flags & flag))
4147                         R_Shadow_DrawLight(&light->rtlight);
4148         }
4149         else
4150         {
4151                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4152                 for (lightindex = 0;lightindex < range;lightindex++)
4153                 {
4154                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4155                         if (light && (light->flags & flag))
4156                                 R_Shadow_DrawLight(&light->rtlight);
4157                 }
4158         }
4159         if (r_refdef.scene.rtdlight)
4160                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4161                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4162
4163         R_Shadow_RenderMode_End();
4164 }
4165
4166 extern const float r_screenvertex3f[12];
4167 extern void R_SetupView(qboolean allowwaterclippingplane);
4168 extern void R_ResetViewRendering3D(void);
4169 extern void R_ResetViewRendering2D(void);
4170 extern cvar_t r_shadows;
4171 extern cvar_t r_shadows_darken;
4172 extern cvar_t r_shadows_drawafterrtlighting;
4173 extern cvar_t r_shadows_castfrombmodels;
4174 extern cvar_t r_shadows_throwdistance;
4175 extern cvar_t r_shadows_throwdirection;
4176 void R_DrawModelShadows(void)
4177 {
4178         int i;
4179         float relativethrowdistance;
4180         entity_render_t *ent;
4181         vec3_t relativelightorigin;
4182         vec3_t relativelightdirection;
4183         vec3_t relativeshadowmins, relativeshadowmaxs;
4184         vec3_t tmp, shadowdir;
4185
4186         if (!r_refdef.scene.numentities || !vid.stencil)
4187                 return;
4188
4189         CHECKGLERROR
4190         R_ResetViewRendering3D();
4191         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4192         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4193         R_Shadow_RenderMode_Begin();
4194         R_Shadow_RenderMode_ActiveLight(NULL);
4195         r_shadow_lightscissor[0] = r_refdef.view.x;
4196         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4197         r_shadow_lightscissor[2] = r_refdef.view.width;
4198         r_shadow_lightscissor[3] = r_refdef.view.height;
4199         R_Shadow_RenderMode_StencilShadowVolumes(false);
4200
4201         // get shadow dir
4202         if (r_shadows.integer == 2)
4203         {
4204                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4205                 VectorNormalize(shadowdir);
4206         }
4207
4208         R_Shadow_ClearStencil();
4209
4210         for (i = 0;i < r_refdef.scene.numentities;i++)
4211         {
4212                 ent = r_refdef.scene.entities[i];
4213
4214                 // cast shadows from anything of the map (submodels are optional)
4215                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4216                 {
4217                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4218                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4219                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4220                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4221                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4222                         else
4223                         {
4224                                 if(ent->entitynumber != 0)
4225                                 {
4226                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4227                                         int entnum, entnum2, recursion;
4228                                         entnum = entnum2 = ent->entitynumber;
4229                                         for(recursion = 32; recursion > 0; --recursion)
4230                                         {
4231                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
4232                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4233                                                         entnum = entnum2;
4234                                                 else
4235                                                         break;
4236                                         }
4237                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4238                                         {
4239                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4240                                                 // transform into modelspace of OUR entity
4241                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4242                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4243                                         }
4244                                         else
4245                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4246                                 }
4247                                 else
4248                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4249                         }
4250
4251                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4252                         RSurf_ActiveModelEntity(ent, false, false, false);
4253                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4254                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4255                 }
4256         }
4257
4258         // not really the right mode, but this will disable any silly stencil features
4259         R_Shadow_RenderMode_End();
4260
4261         // set up ortho view for rendering this pass
4262         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4263         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4264         //GL_ScissorTest(true);
4265         //R_EntityMatrix(&identitymatrix);
4266         //R_Mesh_ResetTextureState();
4267         R_ResetViewRendering2D();
4268         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4269         R_Mesh_ColorPointer(NULL, 0, 0);
4270         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4271
4272         // set up a darkening blend on shadowed areas
4273         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4274         //GL_DepthRange(0, 1);
4275         //GL_DepthTest(false);
4276         //GL_DepthMask(false);
4277         //GL_PolygonOffset(0, 0);CHECKGLERROR
4278         GL_Color(0, 0, 0, r_shadows_darken.value);
4279         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4280         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4281         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4282         qglStencilMask(~0);CHECKGLERROR
4283         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4284         qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4285
4286         // apply the blend to the shadowed areas
4287         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4288
4289         // restore the viewport
4290         R_SetViewport(&r_refdef.view.viewport);
4291
4292         // restore other state to normal
4293         //R_Shadow_RenderMode_End();
4294 }
4295
4296 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4297 {
4298         float zdist;
4299         vec3_t centerorigin;
4300         float vertex3f[12];
4301         // if it's too close, skip it
4302         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4303                 return;
4304         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4305         if (zdist < 32)
4306                 return;
4307         if (usequery && r_numqueries + 2 <= r_maxqueries)
4308         {
4309                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4310                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4311                 // 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
4312                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4313
4314                 CHECKGLERROR
4315                 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4316                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4317                 qglDepthFunc(GL_ALWAYS);
4318                 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4319                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4320                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4321                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4322                 qglDepthFunc(GL_LEQUAL);
4323                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4324                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, 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                 CHECKGLERROR
4329         }
4330         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4331 }
4332
4333 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4334
4335 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4336 {
4337         vec3_t color;
4338         GLint allpixels = 0, visiblepixels = 0;
4339         // now we have to check the query result
4340         if (rtlight->corona_queryindex_visiblepixels)
4341         {
4342                 CHECKGLERROR
4343                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4344                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4345                 CHECKGLERROR
4346                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4347                 if (visiblepixels < 1 || allpixels < 1)
4348                         return;
4349                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4350                 cscale *= rtlight->corona_visibility;
4351         }
4352         else
4353         {
4354                 // FIXME: these traces should scan all render entities instead of cl.world
4355                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4356                         return;
4357         }
4358         VectorScale(rtlight->currentcolor, cscale, color);
4359         if (VectorLength(color) > (1.0f / 256.0f))
4360         {
4361                 float vertex3f[12];
4362                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4363                 if(negated)
4364                 {
4365                         VectorNegate(color, color);
4366                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4367                 }
4368                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4369                 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);
4370                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4371                 if(negated)
4372                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4373         }
4374 }
4375
4376 void R_Shadow_DrawCoronas(void)
4377 {
4378         int i, flag;
4379         qboolean usequery;
4380         size_t lightindex;
4381         dlight_t *light;
4382         rtlight_t *rtlight;
4383         size_t range;
4384         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4385                 return;
4386         if (r_waterstate.renderingscene)
4387                 return;
4388         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4389         R_EntityMatrix(&identitymatrix);
4390
4391         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4392
4393         // check occlusion of coronas
4394         // use GL_ARB_occlusion_query if available
4395         // otherwise use raytraces
4396         r_numqueries = 0;
4397         usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4398         if (usequery)
4399         {
4400                 GL_ColorMask(0,0,0,0);
4401                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4402                 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4403                 {
4404                         i = r_maxqueries;
4405                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4406                         r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4407                         CHECKGLERROR
4408                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4409                         CHECKGLERROR
4410                 }
4411                 RSurf_ActiveWorldEntity();
4412                 GL_BlendFunc(GL_ONE, GL_ZERO);
4413                 GL_CullFace(GL_NONE);
4414                 GL_DepthMask(false);
4415                 GL_DepthRange(0, 1);
4416                 GL_PolygonOffset(0, 0);
4417                 GL_DepthTest(true);
4418                 R_Mesh_ColorPointer(NULL, 0, 0);
4419                 R_Mesh_ResetTextureState();
4420                 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4421         }
4422         for (lightindex = 0;lightindex < range;lightindex++)
4423         {
4424                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4425                 if (!light)
4426                         continue;
4427                 rtlight = &light->rtlight;
4428                 rtlight->corona_visibility = 0;
4429                 rtlight->corona_queryindex_visiblepixels = 0;
4430                 rtlight->corona_queryindex_allpixels = 0;
4431                 if (!(rtlight->flags & flag))
4432                         continue;
4433                 if (rtlight->corona <= 0)
4434                         continue;
4435                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4436                         continue;
4437                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4438         }
4439         for (i = 0;i < r_refdef.scene.numlights;i++)
4440         {
4441                 rtlight = r_refdef.scene.lights[i];
4442                 rtlight->corona_visibility = 0;
4443                 rtlight->corona_queryindex_visiblepixels = 0;
4444                 rtlight->corona_queryindex_allpixels = 0;
4445                 if (!(rtlight->flags & flag))
4446                         continue;
4447                 if (rtlight->corona <= 0)
4448                         continue;
4449                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4450         }
4451         if (usequery)
4452                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4453
4454         // now draw the coronas using the query data for intensity info
4455         for (lightindex = 0;lightindex < range;lightindex++)
4456         {
4457                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4458                 if (!light)
4459                         continue;
4460                 rtlight = &light->rtlight;
4461                 if (rtlight->corona_visibility <= 0)
4462                         continue;
4463                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4464         }
4465         for (i = 0;i < r_refdef.scene.numlights;i++)
4466         {
4467                 rtlight = r_refdef.scene.lights[i];
4468                 if (rtlight->corona_visibility <= 0)
4469                         continue;
4470                 if (gl_flashblend.integer)
4471                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4472                 else
4473                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4474         }
4475 }
4476
4477
4478
4479 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4480 typedef struct suffixinfo_s
4481 {
4482         char *suffix;
4483         qboolean flipx, flipy, flipdiagonal;
4484 }
4485 suffixinfo_t;
4486 static suffixinfo_t suffix[3][6] =
4487 {
4488         {
4489                 {"px",   false, false, false},
4490                 {"nx",   false, false, false},
4491                 {"py",   false, false, false},
4492                 {"ny",   false, false, false},
4493                 {"pz",   false, false, false},
4494                 {"nz",   false, false, false}
4495         },
4496         {
4497                 {"posx", false, false, false},
4498                 {"negx", false, false, false},
4499                 {"posy", false, false, false},
4500                 {"negy", false, false, false},
4501                 {"posz", false, false, false},
4502                 {"negz", false, false, false}
4503         },
4504         {
4505                 {"rt",    true, false,  true},
4506                 {"lf",   false,  true,  true},
4507                 {"ft",    true,  true, false},
4508                 {"bk",   false, false, false},
4509                 {"up",    true, false,  true},
4510                 {"dn",    true, false,  true}
4511         }
4512 };
4513
4514 static int componentorder[4] = {0, 1, 2, 3};
4515
4516 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4517 {
4518         int i, j, cubemapsize;
4519         unsigned char *cubemappixels, *image_buffer;
4520         rtexture_t *cubemaptexture;
4521         char name[256];
4522         // must start 0 so the first loadimagepixels has no requested width/height
4523         cubemapsize = 0;
4524         cubemappixels = NULL;
4525         cubemaptexture = NULL;
4526         // keep trying different suffix groups (posx, px, rt) until one loads
4527         for (j = 0;j < 3 && !cubemappixels;j++)
4528         {
4529                 // load the 6 images in the suffix group
4530                 for (i = 0;i < 6;i++)
4531                 {
4532                         // generate an image name based on the base and and suffix
4533                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4534                         // load it
4535                         if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4536                         {
4537                                 // an image loaded, make sure width and height are equal
4538                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4539                                 {
4540                                         // if this is the first image to load successfully, allocate the cubemap memory
4541                                         if (!cubemappixels && image_width >= 1)
4542                                         {
4543                                                 cubemapsize = image_width;
4544                                                 // note this clears to black, so unavailable sides are black
4545                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4546                                         }
4547                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4548                                         if (cubemappixels)
4549                                                 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);
4550                                 }
4551                                 else
4552                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4553                                 // free the image
4554                                 Mem_Free(image_buffer);
4555                         }
4556                 }
4557         }
4558         // if a cubemap loaded, upload it
4559         if (cubemappixels)
4560         {
4561                 if (developer_loading.integer)
4562                         Con_Printf("loading cubemap \"%s\"\n", basename);
4563
4564                 if (!r_shadow_filters_texturepool)
4565                         r_shadow_filters_texturepool = R_AllocTexturePool();
4566                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4567                 Mem_Free(cubemappixels);
4568         }
4569         else
4570         {
4571                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4572                 if (developer_loading.integer)
4573                 {
4574                         Con_Printf("(tried tried images ");
4575                         for (j = 0;j < 3;j++)
4576                                 for (i = 0;i < 6;i++)
4577                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4578                         Con_Print(" and was unable to find any of them).\n");
4579                 }
4580         }
4581         return cubemaptexture;
4582 }
4583
4584 rtexture_t *R_Shadow_Cubemap(const char *basename)
4585 {
4586         int i;
4587         for (i = 0;i < numcubemaps;i++)
4588                 if (!strcasecmp(cubemaps[i].basename, basename))
4589                         return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4590         if (i >= MAX_CUBEMAPS)
4591                 return r_texture_whitecube;
4592         numcubemaps++;
4593         strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4594         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4595         return cubemaps[i].texture;
4596 }
4597
4598 void R_Shadow_FreeCubemaps(void)
4599 {
4600         int i;
4601         for (i = 0;i < numcubemaps;i++)
4602         {
4603                 if (developer_loading.integer)
4604                         Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4605                 if (cubemaps[i].texture)
4606                         R_FreeTexture(cubemaps[i].texture);
4607         }
4608
4609         numcubemaps = 0;
4610         R_FreeTexturePool(&r_shadow_filters_texturepool);
4611 }
4612
4613 dlight_t *R_Shadow_NewWorldLight(void)
4614 {
4615         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4616 }
4617
4618 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)
4619 {
4620         matrix4x4_t matrix;
4621         // validate parameters
4622         if (style < 0 || style >= MAX_LIGHTSTYLES)
4623         {
4624                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4625                 style = 0;
4626         }
4627         if (!cubemapname)
4628                 cubemapname = "";
4629
4630         // copy to light properties
4631         VectorCopy(origin, light->origin);
4632         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4633         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4634         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4635         /*
4636         light->color[0] = max(color[0], 0);
4637         light->color[1] = max(color[1], 0);
4638         light->color[2] = max(color[2], 0);
4639         */
4640         light->color[0] = color[0];
4641         light->color[1] = color[1];
4642         light->color[2] = color[2];
4643         light->radius = max(radius, 0);
4644         light->style = style;
4645         light->shadow = shadowenable;
4646         light->corona = corona;
4647         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4648         light->coronasizescale = coronasizescale;
4649         light->ambientscale = ambientscale;
4650         light->diffusescale = diffusescale;
4651         light->specularscale = specularscale;
4652         light->flags = flags;
4653
4654         // update renderable light data
4655         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4656         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);
4657 }
4658
4659 void R_Shadow_FreeWorldLight(dlight_t *light)
4660 {
4661         if (r_shadow_selectedlight == light)
4662                 r_shadow_selectedlight = NULL;
4663         R_RTLight_Uncompile(&light->rtlight);
4664         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4665 }
4666
4667 void R_Shadow_ClearWorldLights(void)
4668 {
4669         size_t lightindex;
4670         dlight_t *light;
4671         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4672         for (lightindex = 0;lightindex < range;lightindex++)
4673         {
4674                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4675                 if (light)
4676                         R_Shadow_FreeWorldLight(light);
4677         }
4678         r_shadow_selectedlight = NULL;
4679         R_Shadow_FreeCubemaps();
4680 }
4681
4682 void R_Shadow_SelectLight(dlight_t *light)
4683 {
4684         if (r_shadow_selectedlight)
4685                 r_shadow_selectedlight->selected = false;
4686         r_shadow_selectedlight = light;
4687         if (r_shadow_selectedlight)
4688                 r_shadow_selectedlight->selected = true;
4689 }
4690
4691 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4692 {
4693         // this is never batched (there can be only one)
4694         float vertex3f[12];
4695         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4696         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4697         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4698 }
4699
4700 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4701 {
4702         float intensity;
4703         float s;
4704         vec3_t spritecolor;
4705         skinframe_t *skinframe;
4706         float vertex3f[12];
4707
4708         // this is never batched (due to the ent parameter changing every time)
4709         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4710         const dlight_t *light = (dlight_t *)ent;
4711         s = EDLIGHTSPRSIZE;
4712
4713         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4714
4715         intensity = 0.5f;
4716         VectorScale(light->color, intensity, spritecolor);
4717         if (VectorLength(spritecolor) < 0.1732f)
4718                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4719         if (VectorLength(spritecolor) > 1.0f)
4720                 VectorNormalize(spritecolor);
4721
4722         // draw light sprite
4723         if (light->cubemapname[0] && !light->shadow)
4724                 skinframe = r_editlights_sprcubemapnoshadowlight;
4725         else if (light->cubemapname[0])
4726                 skinframe = r_editlights_sprcubemaplight;
4727         else if (!light->shadow)
4728                 skinframe = r_editlights_sprnoshadowlight;
4729         else
4730                 skinframe = r_editlights_sprlight;
4731
4732         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);
4733         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4734
4735         // draw selection sprite if light is selected
4736         if (light->selected)
4737         {
4738                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4739                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4740                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4741         }
4742 }
4743
4744 void R_Shadow_DrawLightSprites(void)
4745 {
4746         size_t lightindex;
4747         dlight_t *light;
4748         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4749         for (lightindex = 0;lightindex < range;lightindex++)
4750         {
4751                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4752                 if (light)
4753                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4754         }
4755         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4756 }
4757
4758 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4759 {
4760         unsigned int range;
4761         dlight_t *light;
4762         rtlight_t *rtlight;
4763         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4764         if (lightindex >= range)
4765                 return -1;
4766         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4767         if (!light)
4768                 return 0;
4769         rtlight = &light->rtlight;
4770         //if (!(rtlight->flags & flag))
4771         //      return 0;
4772         VectorCopy(rtlight->shadoworigin, origin);
4773         *radius = rtlight->radius;
4774         VectorCopy(rtlight->color, color);
4775         return 1;
4776 }
4777
4778 void R_Shadow_SelectLightInView(void)
4779 {
4780         float bestrating, rating, temp[3];
4781         dlight_t *best;
4782         size_t lightindex;
4783         dlight_t *light;
4784         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4785         best = NULL;
4786         bestrating = 0;
4787         for (lightindex = 0;lightindex < range;lightindex++)
4788         {
4789                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4790                 if (!light)
4791                         continue;
4792                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4793                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4794                 if (rating >= 0.95)
4795                 {
4796                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4797                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4798                         {
4799                                 bestrating = rating;
4800                                 best = light;
4801                         }
4802                 }
4803         }
4804         R_Shadow_SelectLight(best);
4805 }
4806
4807 void R_Shadow_LoadWorldLights(void)
4808 {
4809         int n, a, style, shadow, flags;
4810         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4811         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4812         if (cl.worldmodel == NULL)
4813         {
4814                 Con_Print("No map loaded.\n");
4815                 return;
4816         }
4817         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4818         strlcat (name, ".rtlights", sizeof (name));
4819         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4820         if (lightsstring)
4821         {
4822                 s = lightsstring;
4823                 n = 0;
4824                 while (*s)
4825                 {
4826                         t = s;
4827                         /*
4828                         shadow = true;
4829                         for (;COM_Parse(t, true) && strcmp(
4830                         if (COM_Parse(t, true))
4831                         {
4832                                 if (com_token[0] == '!')
4833                                 {
4834                                         shadow = false;
4835                                         origin[0] = atof(com_token+1);
4836                                 }
4837                                 else
4838                                         origin[0] = atof(com_token);
4839                                 if (Com_Parse(t
4840                         }
4841                         */
4842                         t = s;
4843                         while (*s && *s != '\n' && *s != '\r')
4844                                 s++;
4845                         if (!*s)
4846                                 break;
4847                         tempchar = *s;
4848                         shadow = true;
4849                         // check for modifier flags
4850                         if (*t == '!')
4851                         {
4852                                 shadow = false;
4853                                 t++;
4854                         }
4855                         *s = 0;
4856 #if _MSC_VER >= 1400
4857 #define sscanf sscanf_s
4858 #endif
4859                         cubemapname[sizeof(cubemapname)-1] = 0;
4860 #if MAX_QPATH != 128
4861 #error update this code if MAX_QPATH changes
4862 #endif
4863                         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
4864 #if _MSC_VER >= 1400
4865 , sizeof(cubemapname)
4866 #endif
4867 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4868                         *s = tempchar;
4869                         if (a < 18)
4870                                 flags = LIGHTFLAG_REALTIMEMODE;
4871                         if (a < 17)
4872                                 specularscale = 1;
4873                         if (a < 16)
4874                                 diffusescale = 1;
4875                         if (a < 15)
4876                                 ambientscale = 0;
4877                         if (a < 14)
4878                                 coronasizescale = 0.25f;
4879                         if (a < 13)
4880                                 VectorClear(angles);
4881                         if (a < 10)
4882                                 corona = 0;
4883                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4884                                 cubemapname[0] = 0;
4885                         // remove quotes on cubemapname
4886                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4887                         {
4888                                 size_t namelen;
4889                                 namelen = strlen(cubemapname) - 2;
4890                                 memmove(cubemapname, cubemapname + 1, namelen);
4891                                 cubemapname[namelen] = '\0';
4892                         }
4893                         if (a < 8)
4894                         {
4895                                 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);
4896                                 break;
4897                         }
4898                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4899                         if (*s == '\r')
4900                                 s++;
4901                         if (*s == '\n')
4902                                 s++;
4903                         n++;
4904                 }
4905                 if (*s)
4906                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4907                 Mem_Free(lightsstring);
4908         }
4909 }
4910
4911 void R_Shadow_SaveWorldLights(void)
4912 {
4913         size_t lightindex;
4914         dlight_t *light;
4915         size_t bufchars, bufmaxchars;
4916         char *buf, *oldbuf;
4917         char name[MAX_QPATH];
4918         char line[MAX_INPUTLINE];
4919         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4920         // I hate lines which are 3 times my screen size :( --blub
4921         if (!range)
4922                 return;
4923         if (cl.worldmodel == NULL)
4924         {
4925                 Con_Print("No map loaded.\n");
4926                 return;
4927         }
4928         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4929         strlcat (name, ".rtlights", sizeof (name));
4930         bufchars = bufmaxchars = 0;
4931         buf = NULL;
4932         for (lightindex = 0;lightindex < range;lightindex++)
4933         {
4934                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4935                 if (!light)
4936                         continue;
4937                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4938                         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);
4939                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4940                         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]);
4941                 else
4942                         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);
4943                 if (bufchars + strlen(line) > bufmaxchars)
4944                 {
4945                         bufmaxchars = bufchars + strlen(line) + 2048;
4946                         oldbuf = buf;
4947                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4948                         if (oldbuf)
4949                         {
4950                                 if (bufchars)
4951                                         memcpy(buf, oldbuf, bufchars);
4952                                 Mem_Free(oldbuf);
4953                         }
4954                 }
4955                 if (strlen(line))
4956                 {
4957                         memcpy(buf + bufchars, line, strlen(line));
4958                         bufchars += strlen(line);
4959                 }
4960         }
4961         if (bufchars)
4962                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4963         if (buf)
4964                 Mem_Free(buf);
4965 }
4966
4967 void R_Shadow_LoadLightsFile(void)
4968 {
4969         int n, a, style;
4970         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4971         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4972         if (cl.worldmodel == NULL)
4973         {
4974                 Con_Print("No map loaded.\n");
4975                 return;
4976         }
4977         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4978         strlcat (name, ".lights", sizeof (name));
4979         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4980         if (lightsstring)
4981         {
4982                 s = lightsstring;
4983                 n = 0;
4984                 while (*s)
4985                 {
4986                         t = s;
4987                         while (*s && *s != '\n' && *s != '\r')
4988                                 s++;
4989                         if (!*s)
4990                                 break;
4991                         tempchar = *s;
4992                         *s = 0;
4993                         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);
4994                         *s = tempchar;
4995                         if (a < 14)
4996                         {
4997                                 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);
4998                                 break;
4999                         }
5000                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5001                         radius = bound(15, radius, 4096);
5002                         VectorScale(color, (2.0f / (8388608.0f)), color);
5003                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5004                         if (*s == '\r')
5005                                 s++;
5006                         if (*s == '\n')
5007                                 s++;
5008                         n++;
5009                 }
5010                 if (*s)
5011                         Con_Printf("invalid lights file \"%s\"\n", name);
5012                 Mem_Free(lightsstring);
5013         }
5014 }
5015
5016 // tyrlite/hmap2 light types in the delay field
5017 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5018
5019 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5020 {
5021         int entnum, style, islight, skin, pflags, effects, type, n;
5022         char *entfiledata;
5023         const char *data;
5024         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5025         char key[256], value[MAX_INPUTLINE];
5026
5027         if (cl.worldmodel == NULL)
5028         {
5029                 Con_Print("No map loaded.\n");
5030                 return;
5031         }
5032         // try to load a .ent file first
5033         FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5034         strlcat (key, ".ent", sizeof (key));
5035         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5036         // and if that is not found, fall back to the bsp file entity string
5037         if (!data)
5038                 data = cl.worldmodel->brush.entities;
5039         if (!data)
5040                 return;
5041         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5042         {
5043                 type = LIGHTTYPE_MINUSX;
5044                 origin[0] = origin[1] = origin[2] = 0;
5045                 originhack[0] = originhack[1] = originhack[2] = 0;
5046                 angles[0] = angles[1] = angles[2] = 0;
5047                 color[0] = color[1] = color[2] = 1;
5048                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5049                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5050                 fadescale = 1;
5051                 lightscale = 1;
5052                 style = 0;
5053                 skin = 0;
5054                 pflags = 0;
5055                 effects = 0;
5056                 islight = false;
5057                 while (1)
5058                 {
5059                         if (!COM_ParseToken_Simple(&data, false, false))
5060                                 break; // error
5061                         if (com_token[0] == '}')
5062                                 break; // end of entity
5063                         if (com_token[0] == '_')
5064                                 strlcpy(key, com_token + 1, sizeof(key));
5065                         else
5066                                 strlcpy(key, com_token, sizeof(key));
5067                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5068                                 key[strlen(key)-1] = 0;
5069                         if (!COM_ParseToken_Simple(&data, false, false))
5070                                 break; // error
5071                         strlcpy(value, com_token, sizeof(value));
5072
5073                         // now that we have the key pair worked out...
5074                         if (!strcmp("light", key))
5075                         {
5076                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5077                                 if (n == 1)
5078                                 {
5079                                         // quake
5080                                         light[0] = vec[0] * (1.0f / 256.0f);
5081                                         light[1] = vec[0] * (1.0f / 256.0f);
5082                                         light[2] = vec[0] * (1.0f / 256.0f);
5083                                         light[3] = vec[0];
5084                                 }
5085                                 else if (n == 4)
5086                                 {
5087                                         // halflife
5088                                         light[0] = vec[0] * (1.0f / 255.0f);
5089                                         light[1] = vec[1] * (1.0f / 255.0f);
5090                                         light[2] = vec[2] * (1.0f / 255.0f);
5091                                         light[3] = vec[3];
5092                                 }
5093                         }
5094                         else if (!strcmp("delay", key))
5095                                 type = atoi(value);
5096                         else if (!strcmp("origin", key))
5097                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5098                         else if (!strcmp("angle", key))
5099                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5100                         else if (!strcmp("angles", key))
5101                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5102                         else if (!strcmp("color", key))
5103                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5104                         else if (!strcmp("wait", key))
5105                                 fadescale = atof(value);
5106                         else if (!strcmp("classname", key))
5107                         {
5108                                 if (!strncmp(value, "light", 5))
5109                                 {
5110                                         islight = true;
5111                                         if (!strcmp(value, "light_fluoro"))
5112                                         {
5113                                                 originhack[0] = 0;
5114                                                 originhack[1] = 0;
5115                                                 originhack[2] = 0;
5116                                                 overridecolor[0] = 1;
5117                                                 overridecolor[1] = 1;
5118                                                 overridecolor[2] = 1;
5119                                         }
5120                                         if (!strcmp(value, "light_fluorospark"))
5121                                         {
5122                                                 originhack[0] = 0;
5123                                                 originhack[1] = 0;
5124                                                 originhack[2] = 0;
5125                                                 overridecolor[0] = 1;
5126                                                 overridecolor[1] = 1;
5127                                                 overridecolor[2] = 1;
5128                                         }
5129                                         if (!strcmp(value, "light_globe"))
5130                                         {
5131                                                 originhack[0] = 0;
5132                                                 originhack[1] = 0;
5133                                                 originhack[2] = 0;
5134                                                 overridecolor[0] = 1;
5135                                                 overridecolor[1] = 0.8;
5136                                                 overridecolor[2] = 0.4;
5137                                         }
5138                                         if (!strcmp(value, "light_flame_large_yellow"))
5139                                         {
5140                                                 originhack[0] = 0;
5141                                                 originhack[1] = 0;
5142                                                 originhack[2] = 0;
5143                                                 overridecolor[0] = 1;
5144                                                 overridecolor[1] = 0.5;
5145                                                 overridecolor[2] = 0.1;
5146                                         }
5147                                         if (!strcmp(value, "light_flame_small_yellow"))
5148                                         {
5149                                                 originhack[0] = 0;
5150                                                 originhack[1] = 0;
5151                                                 originhack[2] = 0;
5152                                                 overridecolor[0] = 1;
5153                                                 overridecolor[1] = 0.5;
5154                                                 overridecolor[2] = 0.1;
5155                                         }
5156                                         if (!strcmp(value, "light_torch_small_white"))
5157                                         {
5158                                                 originhack[0] = 0;
5159                                                 originhack[1] = 0;
5160                                                 originhack[2] = 0;
5161                                                 overridecolor[0] = 1;
5162                                                 overridecolor[1] = 0.5;
5163                                                 overridecolor[2] = 0.1;
5164                                         }
5165                                         if (!strcmp(value, "light_torch_small_walltorch"))
5166                                         {
5167                                                 originhack[0] = 0;
5168                                                 originhack[1] = 0;
5169                                                 originhack[2] = 0;
5170                                                 overridecolor[0] = 1;
5171                                                 overridecolor[1] = 0.5;
5172                                                 overridecolor[2] = 0.1;
5173                                         }
5174                                 }
5175                         }
5176                         else if (!strcmp("style", key))
5177                                 style = atoi(value);
5178                         else if (!strcmp("skin", key))
5179                                 skin = (int)atof(value);
5180                         else if (!strcmp("pflags", key))
5181                                 pflags = (int)atof(value);
5182                         else if (!strcmp("effects", key))
5183                                 effects = (int)atof(value);
5184                         else if (cl.worldmodel->type == mod_brushq3)
5185                         {
5186                                 if (!strcmp("scale", key))
5187                                         lightscale = atof(value);
5188                                 if (!strcmp("fade", key))
5189                                         fadescale = atof(value);
5190                         }
5191                 }
5192                 if (!islight)
5193                         continue;
5194                 if (lightscale <= 0)
5195                         lightscale = 1;
5196                 if (fadescale <= 0)
5197                         fadescale = 1;
5198                 if (color[0] == color[1] && color[0] == color[2])
5199                 {
5200                         color[0] *= overridecolor[0];
5201                         color[1] *= overridecolor[1];
5202                         color[2] *= overridecolor[2];
5203                 }
5204                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5205                 color[0] = color[0] * light[0];
5206                 color[1] = color[1] * light[1];
5207                 color[2] = color[2] * light[2];
5208                 switch (type)
5209                 {
5210                 case LIGHTTYPE_MINUSX:
5211                         break;
5212                 case LIGHTTYPE_RECIPX:
5213                         radius *= 2;
5214                         VectorScale(color, (1.0f / 16.0f), color);
5215                         break;
5216                 case LIGHTTYPE_RECIPXX:
5217                         radius *= 2;
5218                         VectorScale(color, (1.0f / 16.0f), color);
5219                         break;
5220                 default:
5221                 case LIGHTTYPE_NONE:
5222                         break;
5223                 case LIGHTTYPE_SUN:
5224                         break;
5225                 case LIGHTTYPE_MINUSXX:
5226                         break;
5227                 }
5228                 VectorAdd(origin, originhack, origin);
5229                 if (radius >= 1)
5230                         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);
5231         }
5232         if (entfiledata)
5233                 Mem_Free(entfiledata);
5234 }
5235
5236
5237 void R_Shadow_SetCursorLocationForView(void)
5238 {
5239         vec_t dist, push;
5240         vec3_t dest, endpos;
5241         trace_t trace;
5242         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5243         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5244         if (trace.fraction < 1)
5245         {
5246                 dist = trace.fraction * r_editlights_cursordistance.value;
5247                 push = r_editlights_cursorpushback.value;
5248                 if (push > dist)
5249                         push = dist;
5250                 push = -push;
5251                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5252                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5253         }
5254         else
5255         {
5256                 VectorClear( endpos );
5257         }
5258         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5259         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5260         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5261 }
5262
5263 void R_Shadow_UpdateWorldLightSelection(void)
5264 {
5265         if (r_editlights.integer)
5266         {
5267                 R_Shadow_SetCursorLocationForView();
5268                 R_Shadow_SelectLightInView();
5269         }
5270         else
5271                 R_Shadow_SelectLight(NULL);
5272 }
5273
5274 void R_Shadow_EditLights_Clear_f(void)
5275 {
5276         R_Shadow_ClearWorldLights();
5277 }
5278
5279 void R_Shadow_EditLights_Reload_f(void)
5280 {
5281         if (!cl.worldmodel)
5282                 return;
5283         strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5284         R_Shadow_ClearWorldLights();
5285         R_Shadow_LoadWorldLights();
5286         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5287         {
5288                 R_Shadow_LoadLightsFile();
5289                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5290                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5291         }
5292 }
5293
5294 void R_Shadow_EditLights_Save_f(void)
5295 {
5296         if (!cl.worldmodel)
5297                 return;
5298         R_Shadow_SaveWorldLights();
5299 }
5300
5301 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5302 {
5303         R_Shadow_ClearWorldLights();
5304         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5305 }
5306
5307 void R_Shadow_EditLights_ImportLightsFile_f(void)
5308 {
5309         R_Shadow_ClearWorldLights();
5310         R_Shadow_LoadLightsFile();
5311 }
5312
5313 void R_Shadow_EditLights_Spawn_f(void)
5314 {
5315         vec3_t color;
5316         if (!r_editlights.integer)
5317         {
5318                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5319                 return;
5320         }
5321         if (Cmd_Argc() != 1)
5322         {
5323                 Con_Print("r_editlights_spawn does not take parameters\n");
5324                 return;
5325         }
5326         color[0] = color[1] = color[2] = 1;
5327         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5328 }
5329
5330 void R_Shadow_EditLights_Edit_f(void)
5331 {
5332         vec3_t origin, angles, color;
5333         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5334         int style, shadows, flags, normalmode, realtimemode;
5335         char cubemapname[MAX_INPUTLINE];
5336         if (!r_editlights.integer)
5337         {
5338                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5339                 return;
5340         }
5341         if (!r_shadow_selectedlight)
5342         {
5343                 Con_Print("No selected light.\n");
5344                 return;
5345         }
5346         VectorCopy(r_shadow_selectedlight->origin, origin);
5347         VectorCopy(r_shadow_selectedlight->angles, angles);
5348         VectorCopy(r_shadow_selectedlight->color, color);
5349         radius = r_shadow_selectedlight->radius;
5350         style = r_shadow_selectedlight->style;
5351         if (r_shadow_selectedlight->cubemapname)
5352                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5353         else
5354                 cubemapname[0] = 0;
5355         shadows = r_shadow_selectedlight->shadow;
5356         corona = r_shadow_selectedlight->corona;
5357         coronasizescale = r_shadow_selectedlight->coronasizescale;
5358         ambientscale = r_shadow_selectedlight->ambientscale;
5359         diffusescale = r_shadow_selectedlight->diffusescale;
5360         specularscale = r_shadow_selectedlight->specularscale;
5361         flags = r_shadow_selectedlight->flags;
5362         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5363         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5364         if (!strcmp(Cmd_Argv(1), "origin"))
5365         {
5366                 if (Cmd_Argc() != 5)
5367                 {
5368                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5369                         return;
5370                 }
5371                 origin[0] = atof(Cmd_Argv(2));
5372                 origin[1] = atof(Cmd_Argv(3));
5373                 origin[2] = atof(Cmd_Argv(4));
5374         }
5375         else if (!strcmp(Cmd_Argv(1), "originx"))
5376         {
5377                 if (Cmd_Argc() != 3)
5378                 {
5379                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5380                         return;
5381                 }
5382                 origin[0] = atof(Cmd_Argv(2));
5383         }
5384         else if (!strcmp(Cmd_Argv(1), "originy"))
5385         {
5386                 if (Cmd_Argc() != 3)
5387                 {
5388                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5389                         return;
5390                 }
5391                 origin[1] = atof(Cmd_Argv(2));
5392         }
5393         else if (!strcmp(Cmd_Argv(1), "originz"))
5394         {
5395                 if (Cmd_Argc() != 3)
5396                 {
5397                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5398                         return;
5399                 }
5400                 origin[2] = atof(Cmd_Argv(2));
5401         }
5402         else if (!strcmp(Cmd_Argv(1), "move"))
5403         {
5404                 if (Cmd_Argc() != 5)
5405                 {
5406                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5407                         return;
5408                 }
5409                 origin[0] += atof(Cmd_Argv(2));
5410                 origin[1] += atof(Cmd_Argv(3));
5411                 origin[2] += atof(Cmd_Argv(4));
5412         }
5413         else if (!strcmp(Cmd_Argv(1), "movex"))
5414         {
5415                 if (Cmd_Argc() != 3)
5416                 {
5417                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5418                         return;
5419                 }
5420                 origin[0] += atof(Cmd_Argv(2));
5421         }
5422         else if (!strcmp(Cmd_Argv(1), "movey"))
5423         {
5424                 if (Cmd_Argc() != 3)
5425                 {
5426                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5427                         return;
5428                 }
5429                 origin[1] += atof(Cmd_Argv(2));
5430         }
5431         else if (!strcmp(Cmd_Argv(1), "movez"))
5432         {
5433                 if (Cmd_Argc() != 3)
5434                 {
5435                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5436                         return;
5437                 }
5438                 origin[2] += atof(Cmd_Argv(2));
5439         }
5440         else if (!strcmp(Cmd_Argv(1), "angles"))
5441         {
5442                 if (Cmd_Argc() != 5)
5443                 {
5444                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5445                         return;
5446                 }
5447                 angles[0] = atof(Cmd_Argv(2));
5448                 angles[1] = atof(Cmd_Argv(3));
5449                 angles[2] = atof(Cmd_Argv(4));
5450         }
5451         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5452         {
5453                 if (Cmd_Argc() != 3)
5454                 {
5455                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5456                         return;
5457                 }
5458                 angles[0] = atof(Cmd_Argv(2));
5459         }
5460         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5461         {
5462                 if (Cmd_Argc() != 3)
5463                 {
5464                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5465                         return;
5466                 }
5467                 angles[1] = atof(Cmd_Argv(2));
5468         }
5469         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5470         {
5471                 if (Cmd_Argc() != 3)
5472                 {
5473                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5474                         return;
5475                 }
5476                 angles[2] = atof(Cmd_Argv(2));
5477         }
5478         else if (!strcmp(Cmd_Argv(1), "color"))
5479         {
5480                 if (Cmd_Argc() != 5)
5481                 {
5482                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5483                         return;
5484                 }
5485                 color[0] = atof(Cmd_Argv(2));
5486                 color[1] = atof(Cmd_Argv(3));
5487                 color[2] = atof(Cmd_Argv(4));
5488         }
5489         else if (!strcmp(Cmd_Argv(1), "radius"))
5490         {
5491                 if (Cmd_Argc() != 3)
5492                 {
5493                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5494                         return;
5495                 }
5496                 radius = atof(Cmd_Argv(2));
5497         }
5498         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5499         {
5500                 if (Cmd_Argc() == 3)
5501                 {
5502                         double scale = atof(Cmd_Argv(2));
5503                         color[0] *= scale;
5504                         color[1] *= scale;
5505                         color[2] *= scale;
5506                 }
5507                 else
5508                 {
5509                         if (Cmd_Argc() != 5)
5510                         {
5511                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5512                                 return;
5513                         }
5514                         color[0] *= atof(Cmd_Argv(2));
5515                         color[1] *= atof(Cmd_Argv(3));
5516                         color[2] *= atof(Cmd_Argv(4));
5517                 }
5518         }
5519         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5520         {
5521                 if (Cmd_Argc() != 3)
5522                 {
5523                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5524                         return;
5525                 }
5526                 radius *= atof(Cmd_Argv(2));
5527         }
5528         else if (!strcmp(Cmd_Argv(1), "style"))
5529         {
5530                 if (Cmd_Argc() != 3)
5531                 {
5532                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5533                         return;
5534                 }
5535                 style = atoi(Cmd_Argv(2));
5536         }
5537         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5538         {
5539                 if (Cmd_Argc() > 3)
5540                 {
5541                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5542                         return;
5543                 }
5544                 if (Cmd_Argc() == 3)
5545                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5546                 else
5547                         cubemapname[0] = 0;
5548         }
5549         else if (!strcmp(Cmd_Argv(1), "shadows"))
5550         {
5551                 if (Cmd_Argc() != 3)
5552                 {
5553                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5554                         return;
5555                 }
5556                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5557         }
5558         else if (!strcmp(Cmd_Argv(1), "corona"))
5559         {
5560                 if (Cmd_Argc() != 3)
5561                 {
5562                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5563                         return;
5564                 }
5565                 corona = atof(Cmd_Argv(2));
5566         }
5567         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5568         {
5569                 if (Cmd_Argc() != 3)
5570                 {
5571                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5572                         return;
5573                 }
5574                 coronasizescale = atof(Cmd_Argv(2));
5575         }
5576         else if (!strcmp(Cmd_Argv(1), "ambient"))
5577         {
5578                 if (Cmd_Argc() != 3)
5579                 {
5580                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5581                         return;
5582                 }
5583                 ambientscale = atof(Cmd_Argv(2));
5584         }
5585         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5586         {
5587                 if (Cmd_Argc() != 3)
5588                 {
5589                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5590                         return;
5591                 }
5592                 diffusescale = atof(Cmd_Argv(2));
5593         }
5594         else if (!strcmp(Cmd_Argv(1), "specular"))
5595         {
5596                 if (Cmd_Argc() != 3)
5597                 {
5598                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5599                         return;
5600                 }
5601                 specularscale = atof(Cmd_Argv(2));
5602         }
5603         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5604         {
5605                 if (Cmd_Argc() != 3)
5606                 {
5607                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5608                         return;
5609                 }
5610                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5611         }
5612         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5613         {
5614                 if (Cmd_Argc() != 3)
5615                 {
5616                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5617                         return;
5618                 }
5619                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5620         }
5621         else
5622         {
5623                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5624                 Con_Print("Selected light's properties:\n");
5625                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5626                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5627                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5628                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5629                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5630                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5631                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5632                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5633                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5634                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5635                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5636                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5637                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5638                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5639                 return;
5640         }
5641         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5642         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5643 }
5644
5645 void R_Shadow_EditLights_EditAll_f(void)
5646 {
5647         size_t lightindex;
5648         dlight_t *light;
5649         size_t range;
5650
5651         if (!r_editlights.integer)
5652         {
5653                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5654                 return;
5655         }
5656
5657         // EditLights doesn't seem to have a "remove" command or something so:
5658         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5659         for (lightindex = 0;lightindex < range;lightindex++)
5660         {
5661                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5662                 if (!light)
5663                         continue;
5664                 R_Shadow_SelectLight(light);
5665                 R_Shadow_EditLights_Edit_f();
5666         }
5667 }
5668
5669 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5670 {
5671         int lightnumber, lightcount;
5672         size_t lightindex, range;
5673         dlight_t *light;
5674         float x, y;
5675         char temp[256];
5676         if (!r_editlights.integer)
5677                 return;
5678         x = vid_conwidth.value - 240;
5679         y = 5;
5680         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5681         lightnumber = -1;
5682         lightcount = 0;
5683         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5684         for (lightindex = 0;lightindex < range;lightindex++)
5685         {
5686                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5687                 if (!light)
5688                         continue;
5689                 if (light == r_shadow_selectedlight)
5690                         lightnumber = lightindex;
5691                 lightcount++;
5692         }
5693         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;
5694         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;
5695         y += 8;
5696         if (r_shadow_selectedlight == NULL)
5697                 return;
5698         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;
5699         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;
5700         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;
5701         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;
5702         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;
5703         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;
5704         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;
5705         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;
5706         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;
5707         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;
5708         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;
5709         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;
5710         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;
5711         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;
5712         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;
5713 }
5714
5715 void R_Shadow_EditLights_ToggleShadow_f(void)
5716 {
5717         if (!r_editlights.integer)
5718         {
5719                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5720                 return;
5721         }
5722         if (!r_shadow_selectedlight)
5723         {
5724                 Con_Print("No selected light.\n");
5725                 return;
5726         }
5727         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);
5728 }
5729
5730 void R_Shadow_EditLights_ToggleCorona_f(void)
5731 {
5732         if (!r_editlights.integer)
5733         {
5734                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5735                 return;
5736         }
5737         if (!r_shadow_selectedlight)
5738         {
5739                 Con_Print("No selected light.\n");
5740                 return;
5741         }
5742         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);
5743 }
5744
5745 void R_Shadow_EditLights_Remove_f(void)
5746 {
5747         if (!r_editlights.integer)
5748         {
5749                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5750                 return;
5751         }
5752         if (!r_shadow_selectedlight)
5753         {
5754                 Con_Print("No selected light.\n");
5755                 return;
5756         }
5757         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5758         r_shadow_selectedlight = NULL;
5759 }
5760
5761 void R_Shadow_EditLights_Help_f(void)
5762 {
5763         Con_Print(
5764 "Documentation on r_editlights system:\n"
5765 "Settings:\n"
5766 "r_editlights : enable/disable editing mode\n"
5767 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5768 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5769 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5770 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5771 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5772 "Commands:\n"
5773 "r_editlights_help : this help\n"
5774 "r_editlights_clear : remove all lights\n"
5775 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5776 "r_editlights_save : save to .rtlights file\n"
5777 "r_editlights_spawn : create a light with default settings\n"
5778 "r_editlights_edit command : edit selected light - more documentation below\n"
5779 "r_editlights_remove : remove selected light\n"
5780 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5781 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5782 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5783 "Edit commands:\n"
5784 "origin x y z : set light location\n"
5785 "originx x: set x component of light location\n"
5786 "originy y: set y component of light location\n"
5787 "originz z: set z component of light location\n"
5788 "move x y z : adjust light location\n"
5789 "movex x: adjust x component of light location\n"
5790 "movey y: adjust y component of light location\n"
5791 "movez z: adjust z component of light location\n"
5792 "angles x y z : set light angles\n"
5793 "anglesx x: set x component of light angles\n"
5794 "anglesy y: set y component of light angles\n"
5795 "anglesz z: set z component of light angles\n"
5796 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5797 "radius radius : set radius (size) of light\n"
5798 "colorscale grey : multiply color of light (1 does nothing)\n"
5799 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5800 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5801 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5802 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5803 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5804 "shadows 1/0 : turn on/off shadows\n"
5805 "corona n : set corona intensity\n"
5806 "coronasize n : set corona size (0-1)\n"
5807 "ambient n : set ambient intensity (0-1)\n"
5808 "diffuse n : set diffuse intensity (0-1)\n"
5809 "specular n : set specular intensity (0-1)\n"
5810 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5811 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5812 "<nothing> : print light properties to console\n"
5813         );
5814 }
5815
5816 void R_Shadow_EditLights_CopyInfo_f(void)
5817 {
5818         if (!r_editlights.integer)
5819         {
5820                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5821                 return;
5822         }
5823         if (!r_shadow_selectedlight)
5824         {
5825                 Con_Print("No selected light.\n");
5826                 return;
5827         }
5828         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5829         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5830         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5831         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5832         if (r_shadow_selectedlight->cubemapname)
5833                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5834         else
5835                 r_shadow_bufferlight.cubemapname[0] = 0;
5836         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5837         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5838         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5839         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5840         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5841         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5842         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5843 }
5844
5845 void R_Shadow_EditLights_PasteInfo_f(void)
5846 {
5847         if (!r_editlights.integer)
5848         {
5849                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5850                 return;
5851         }
5852         if (!r_shadow_selectedlight)
5853         {
5854                 Con_Print("No selected light.\n");
5855                 return;
5856         }
5857         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);
5858 }
5859
5860 void R_Shadow_EditLights_Init(void)
5861 {
5862         Cvar_RegisterVariable(&r_editlights);
5863         Cvar_RegisterVariable(&r_editlights_cursordistance);
5864         Cvar_RegisterVariable(&r_editlights_cursorpushback);
5865         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5866         Cvar_RegisterVariable(&r_editlights_cursorgrid);
5867         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5868         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5869         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5870         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)");
5871         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5872         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5873         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5874         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)");
5875         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5876         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5877         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5878         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5879         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5880         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5881         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)");
5882 }
5883
5884
5885
5886 /*
5887 =============================================================================
5888
5889 LIGHT SAMPLING
5890
5891 =============================================================================
5892 */
5893
5894 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5895 {
5896         VectorClear(diffusecolor);
5897         VectorClear(diffusenormal);
5898
5899         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5900         {
5901                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5902                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5903         }
5904         else
5905                 VectorSet(ambientcolor, 1, 1, 1);
5906
5907         if (dynamic)
5908         {
5909                 int i;
5910                 float f, v[3];
5911                 rtlight_t *light;
5912                 for (i = 0;i < r_refdef.scene.numlights;i++)
5913                 {
5914                         light = r_refdef.scene.lights[i];
5915                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5916                         f = 1 - VectorLength2(v);
5917                         if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5918                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
5919                 }
5920         }
5921 }