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