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