]> git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
UNMERGE
[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         int i, ix1, iy1, ix2, iy2;
2452         float x1, y1, x2, y2;
2453         vec4_t v, v2;
2454         float vertex[20][3];
2455         int j, k;
2456         vec4_t plane4f;
2457         int numvertices;
2458         float corner[8][4];
2459         float dist[8];
2460         int sign[8];
2461         float f;
2462
2463         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2464         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2465         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2466         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2467
2468         if (!r_shadow_scissor.integer)
2469                 return false;
2470
2471         // if view is inside the light box, just say yes it's visible
2472         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2473                 return false;
2474
2475         x1 = y1 = x2 = y2 = 0;
2476
2477         // transform all corners that are infront of the nearclip plane
2478         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2479         plane4f[3] = r_refdef.view.frustum[4].dist;
2480         numvertices = 0;
2481         for (i = 0;i < 8;i++)
2482         {
2483                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2484                 dist[i] = DotProduct4(corner[i], plane4f);
2485                 sign[i] = dist[i] > 0;
2486                 if (!sign[i])
2487                 {
2488                         VectorCopy(corner[i], vertex[numvertices]);
2489                         numvertices++;
2490                 }
2491         }
2492         // if some points are behind the nearclip, add clipped edge points to make
2493         // sure that the scissor boundary is complete
2494         if (numvertices > 0 && numvertices < 8)
2495         {
2496                 // add clipped edge points
2497                 for (i = 0;i < 12;i++)
2498                 {
2499                         j = bboxedges[i][0];
2500                         k = bboxedges[i][1];
2501                         if (sign[j] != sign[k])
2502                         {
2503                                 f = dist[j] / (dist[j] - dist[k]);
2504                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2505                                 numvertices++;
2506                         }
2507                 }
2508         }
2509
2510         // if we have no points to check, the light is behind the view plane
2511         if (!numvertices)
2512                 return true;
2513
2514         // if we have some points to transform, check what screen area is covered
2515         x1 = y1 = x2 = y2 = 0;
2516         v[3] = 1.0f;
2517         //Con_Printf("%i vertices to transform...\n", numvertices);
2518         for (i = 0;i < numvertices;i++)
2519         {
2520                 VectorCopy(vertex[i], v);
2521                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2522                 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
2523                 if (i)
2524                 {
2525                         if (x1 > v2[0]) x1 = v2[0];
2526                         if (x2 < v2[0]) x2 = v2[0];
2527                         if (y1 > v2[1]) y1 = v2[1];
2528                         if (y2 < v2[1]) y2 = v2[1];
2529                 }
2530                 else
2531                 {
2532                         x1 = x2 = v2[0];
2533                         y1 = y2 = v2[1];
2534                 }
2535         }
2536
2537         // now convert the scissor rectangle to integer screen coordinates
2538         ix1 = (int)(x1 - 1.0f);
2539         iy1 = vid.height - (int)(y2 - 1.0f);
2540         ix2 = (int)(x2 + 1.0f);
2541         iy2 = vid.height - (int)(y1 + 1.0f);
2542         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2543
2544         // clamp it to the screen
2545         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2546         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2547         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2548         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2549
2550         // if it is inside out, it's not visible
2551         if (ix2 <= ix1 || iy2 <= iy1)
2552                 return true;
2553
2554         // the light area is visible, set up the scissor rectangle
2555         r_shadow_lightscissor[0] = ix1;
2556         r_shadow_lightscissor[1] = iy1;
2557         r_shadow_lightscissor[2] = ix2 - ix1;
2558         r_shadow_lightscissor[3] = iy2 - iy1;
2559
2560         r_refdef.stats.lights_scissored++;
2561         return false;
2562 }
2563
2564 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2565 {
2566         const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2567         const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2568         float *color4f = rsurface.array_color4f + 4 * firstvertex;
2569         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2570         switch (r_shadow_rendermode)
2571         {
2572         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2573         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2574                 if (VectorLength2(diffusecolor) > 0)
2575                 {
2576                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2577                         {
2578                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2579                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2580                                 if ((dot = DotProduct(n, v)) < 0)
2581                                 {
2582                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2583                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2584                                 }
2585                                 else
2586                                         VectorCopy(ambientcolor, color4f);
2587                                 if (r_refdef.fogenabled)
2588                                 {
2589                                         float f;
2590                                         f = RSurf_FogVertex(vertex3f);
2591                                         VectorScale(color4f, f, color4f);
2592                                 }
2593                                 color4f[3] = 1;
2594                         }
2595                 }
2596                 else
2597                 {
2598                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2599                         {
2600                                 VectorCopy(ambientcolor, color4f);
2601                                 if (r_refdef.fogenabled)
2602                                 {
2603                                         float f;
2604                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2605                                         f = RSurf_FogVertex(vertex3f);
2606                                         VectorScale(color4f, f, color4f);
2607                                 }
2608                                 color4f[3] = 1;
2609                         }
2610                 }
2611                 break;
2612         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2613                 if (VectorLength2(diffusecolor) > 0)
2614                 {
2615                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2616                         {
2617                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2618                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2619                                 {
2620                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2621                                         if ((dot = DotProduct(n, v)) < 0)
2622                                         {
2623                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2624                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2625                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2626                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2627                                         }
2628                                         else
2629                                         {
2630                                                 color4f[0] = ambientcolor[0] * distintensity;
2631                                                 color4f[1] = ambientcolor[1] * distintensity;
2632                                                 color4f[2] = ambientcolor[2] * distintensity;
2633                                         }
2634                                         if (r_refdef.fogenabled)
2635                                         {
2636                                                 float f;
2637                                                 f = RSurf_FogVertex(vertex3f);
2638                                                 VectorScale(color4f, f, color4f);
2639                                         }
2640                                 }
2641                                 else
2642                                         VectorClear(color4f);
2643                                 color4f[3] = 1;
2644                         }
2645                 }
2646                 else
2647                 {
2648                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2649                         {
2650                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2651                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2652                                 {
2653                                         color4f[0] = ambientcolor[0] * distintensity;
2654                                         color4f[1] = ambientcolor[1] * distintensity;
2655                                         color4f[2] = ambientcolor[2] * distintensity;
2656                                         if (r_refdef.fogenabled)
2657                                         {
2658                                                 float f;
2659                                                 f = RSurf_FogVertex(vertex3f);
2660                                                 VectorScale(color4f, f, color4f);
2661                                         }
2662                                 }
2663                                 else
2664                                         VectorClear(color4f);
2665                                 color4f[3] = 1;
2666                         }
2667                 }
2668                 break;
2669         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2670                 if (VectorLength2(diffusecolor) > 0)
2671                 {
2672                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2673                         {
2674                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2675                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2676                                 {
2677                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2678                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2679                                         if ((dot = DotProduct(n, v)) < 0)
2680                                         {
2681                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2682                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2683                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2684                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2685                                         }
2686                                         else
2687                                         {
2688                                                 color4f[0] = ambientcolor[0] * distintensity;
2689                                                 color4f[1] = ambientcolor[1] * distintensity;
2690                                                 color4f[2] = ambientcolor[2] * distintensity;
2691                                         }
2692                                         if (r_refdef.fogenabled)
2693                                         {
2694                                                 float f;
2695                                                 f = RSurf_FogVertex(vertex3f);
2696                                                 VectorScale(color4f, f, color4f);
2697                                         }
2698                                 }
2699                                 else
2700                                         VectorClear(color4f);
2701                                 color4f[3] = 1;
2702                         }
2703                 }
2704                 else
2705                 {
2706                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2707                         {
2708                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2709                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2710                                 {
2711                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2712                                         color4f[0] = ambientcolor[0] * distintensity;
2713                                         color4f[1] = ambientcolor[1] * distintensity;
2714                                         color4f[2] = ambientcolor[2] * distintensity;
2715                                         if (r_refdef.fogenabled)
2716                                         {
2717                                                 float f;
2718                                                 f = RSurf_FogVertex(vertex3f);
2719                                                 VectorScale(color4f, f, color4f);
2720                                         }
2721                                 }
2722                                 else
2723                                         VectorClear(color4f);
2724                                 color4f[3] = 1;
2725                         }
2726                 }
2727                 break;
2728         default:
2729                 break;
2730         }
2731 }
2732
2733 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)
2734 {
2735         // used to display how many times a surface is lit for level design purposes
2736         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2737 }
2738
2739 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)
2740 {
2741         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2742         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2743         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2744         {
2745                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2746         }
2747         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2748         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2749         {
2750                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2751         }
2752 }
2753
2754 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2755 {
2756         int renders;
2757         int i;
2758         int stop;
2759         int newfirstvertex;
2760         int newlastvertex;
2761         int newnumtriangles;
2762         int *newe;
2763         const int *e;
2764         float *c;
2765         int maxtriangles = 4096;
2766         static int newelements[4096*3];
2767         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2768         for (renders = 0;renders < 4;renders++)
2769         {
2770                 stop = true;
2771                 newfirstvertex = 0;
2772                 newlastvertex = 0;
2773                 newnumtriangles = 0;
2774                 newe = newelements;
2775                 // due to low fillrate on the cards this vertex lighting path is
2776                 // designed for, we manually cull all triangles that do not
2777                 // contain a lit vertex
2778                 // this builds batches of triangles from multiple surfaces and
2779                 // renders them at once
2780                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2781                 {
2782                         if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2783                         {
2784                                 if (newnumtriangles)
2785                                 {
2786                                         newfirstvertex = min(newfirstvertex, e[0]);
2787                                         newlastvertex  = max(newlastvertex, e[0]);
2788                                 }
2789                                 else
2790                                 {
2791                                         newfirstvertex = e[0];
2792                                         newlastvertex = e[0];
2793                                 }
2794                                 newfirstvertex = min(newfirstvertex, e[1]);
2795                                 newlastvertex  = max(newlastvertex, e[1]);
2796                                 newfirstvertex = min(newfirstvertex, e[2]);
2797                                 newlastvertex  = max(newlastvertex, e[2]);
2798                                 newe[0] = e[0];
2799                                 newe[1] = e[1];
2800                                 newe[2] = e[2];
2801                                 newnumtriangles++;
2802                                 newe += 3;
2803                                 if (newnumtriangles >= maxtriangles)
2804                                 {
2805                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2806                                         newnumtriangles = 0;
2807                                         newe = newelements;
2808                                         stop = false;
2809                                 }
2810                         }
2811                 }
2812                 if (newnumtriangles >= 1)
2813                 {
2814                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2815                         stop = false;
2816                 }
2817                 // if we couldn't find any lit triangles, exit early
2818                 if (stop)
2819                         break;
2820                 // now reduce the intensity for the next overbright pass
2821                 // we have to clamp to 0 here incase the drivers have improper
2822                 // handling of negative colors
2823                 // (some old drivers even have improper handling of >1 color)
2824                 stop = true;
2825                 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2826                 {
2827                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2828                         {
2829                                 c[0] = max(0, c[0] - 1);
2830                                 c[1] = max(0, c[1] - 1);
2831                                 c[2] = max(0, c[2] - 1);
2832                                 stop = false;
2833                         }
2834                         else
2835                                 VectorClear(c);
2836                 }
2837                 // another check...
2838                 if (stop)
2839                         break;
2840         }
2841 }
2842
2843 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2844 {
2845         // OpenGL 1.1 path (anything)
2846         float ambientcolorbase[3], diffusecolorbase[3];
2847         float ambientcolorpants[3], diffusecolorpants[3];
2848         float ambientcolorshirt[3], diffusecolorshirt[3];
2849         const float *surfacecolor = rsurface.texture->dlightcolor;
2850         const float *surfacepants = rsurface.colormap_pantscolor;
2851         const float *surfaceshirt = rsurface.colormap_shirtcolor;
2852         rtexture_t *basetexture = rsurface.texture->basetexture;
2853         rtexture_t *pantstexture = rsurface.texture->pantstexture;
2854         rtexture_t *shirttexture = rsurface.texture->shirttexture;
2855         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2856         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2857         ambientscale *= 2 * r_refdef.view.colorscale;
2858         diffusescale *= 2 * r_refdef.view.colorscale;
2859         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2860         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2861         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2862         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2863         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2864         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2865         R_Mesh_TexBind(0, basetexture);
2866         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2867         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2868         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2869         switch(r_shadow_rendermode)
2870         {
2871         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2872                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2873                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2874                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2875                 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2876                 break;
2877         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2878                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2879                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2880                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2881                 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2882                 // fall through
2883         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2884                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2885                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2886                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2887                 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2888                 break;
2889         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2890                 break;
2891         default:
2892                 break;
2893         }
2894         //R_Mesh_TexBind(0, basetexture);
2895         R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2896         if (dopants)
2897         {
2898                 R_Mesh_TexBind(0, pantstexture);
2899                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2900         }
2901         if (doshirt)
2902         {
2903                 R_Mesh_TexBind(0, shirttexture);
2904                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2905         }
2906 }
2907
2908 extern cvar_t gl_lightmaps;
2909 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)
2910 {
2911         float ambientscale, diffusescale, specularscale;
2912         qboolean negated;
2913         float lightcolor[3];
2914         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2915         ambientscale = rsurface.rtlight->ambientscale;
2916         diffusescale = rsurface.rtlight->diffusescale;
2917         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2918         if (!r_shadow_usenormalmap.integer)
2919         {
2920                 ambientscale += 1.0f * diffusescale;
2921                 diffusescale = 0;
2922                 specularscale = 0;
2923         }
2924         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2925                 return;
2926         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2927         if(negated)
2928         {
2929                 VectorNegate(lightcolor, lightcolor);
2930                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2931         }
2932         RSurf_SetupDepthAndCulling();
2933         switch (r_shadow_rendermode)
2934         {
2935         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2936                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2937                 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2938                 break;
2939         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2940                 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2941                 break;
2942         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2943         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2944         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2945         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2946                 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2947                 break;
2948         default:
2949                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2950                 break;
2951         }
2952         if(negated)
2953                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2954 }
2955
2956 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)
2957 {
2958         matrix4x4_t tempmatrix = *matrix;
2959         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2960
2961         // if this light has been compiled before, free the associated data
2962         R_RTLight_Uncompile(rtlight);
2963
2964         // clear it completely to avoid any lingering data
2965         memset(rtlight, 0, sizeof(*rtlight));
2966
2967         // copy the properties
2968         rtlight->matrix_lighttoworld = tempmatrix;
2969         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2970         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2971         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2972         VectorCopy(color, rtlight->color);
2973         rtlight->cubemapname[0] = 0;
2974         if (cubemapname && cubemapname[0])
2975                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2976         rtlight->shadow = shadow;
2977         rtlight->corona = corona;
2978         rtlight->style = style;
2979         rtlight->isstatic = isstatic;
2980         rtlight->coronasizescale = coronasizescale;
2981         rtlight->ambientscale = ambientscale;
2982         rtlight->diffusescale = diffusescale;
2983         rtlight->specularscale = specularscale;
2984         rtlight->flags = flags;
2985
2986         // compute derived data
2987         //rtlight->cullradius = rtlight->radius;
2988         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2989         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2990         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2991         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2992         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2993         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2994         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2995 }
2996
2997 // compiles rtlight geometry
2998 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2999 void R_RTLight_Compile(rtlight_t *rtlight)
3000 {
3001         int i;
3002         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3003         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3004         entity_render_t *ent = r_refdef.scene.worldentity;
3005         dp_model_t *model = r_refdef.scene.worldmodel;
3006         unsigned char *data;
3007         shadowmesh_t *mesh;
3008
3009         // compile the light
3010         rtlight->compiled = true;
3011         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3012         rtlight->static_numleafs = 0;
3013         rtlight->static_numleafpvsbytes = 0;
3014         rtlight->static_leaflist = NULL;
3015         rtlight->static_leafpvs = NULL;
3016         rtlight->static_numsurfaces = 0;
3017         rtlight->static_surfacelist = NULL;
3018         rtlight->static_shadowmap_receivers = 0x3F;
3019         rtlight->static_shadowmap_casters = 0x3F;
3020         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3021         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3022         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3023         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3024         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3025         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3026
3027         if (model && model->GetLightInfo)
3028         {
3029                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3030                 r_shadow_compilingrtlight = rtlight;
3031                 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);
3032                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3033                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3034                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3035                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3036                 rtlight->static_numsurfaces = numsurfaces;
3037                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3038                 rtlight->static_numleafs = numleafs;
3039                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3040                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3041                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3042                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3043                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3044                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3045                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3046                 if (rtlight->static_numsurfaces)
3047                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3048                 if (rtlight->static_numleafs)
3049                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3050                 if (rtlight->static_numleafpvsbytes)
3051                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3052                 if (rtlight->static_numshadowtrispvsbytes)
3053                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3054                 if (rtlight->static_numlighttrispvsbytes)
3055                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3056                 switch (rtlight->shadowmode)
3057                 {
3058                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3059                 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3060                 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3061                         if (model->CompileShadowMap && rtlight->shadow)
3062                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3063                         break;
3064                 default:
3065                         if (model->CompileShadowVolume && rtlight->shadow)
3066                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3067                         break;
3068                 }
3069                 // now we're done compiling the rtlight
3070                 r_shadow_compilingrtlight = NULL;
3071         }
3072
3073
3074         // use smallest available cullradius - box radius or light radius
3075         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3076         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3077
3078         shadowzpasstris = 0;
3079         if (rtlight->static_meshchain_shadow_zpass)
3080                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3081                         shadowzpasstris += mesh->numtriangles;
3082
3083         shadowzfailtris = 0;
3084         if (rtlight->static_meshchain_shadow_zfail)
3085                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3086                         shadowzfailtris += mesh->numtriangles;
3087
3088         lighttris = 0;
3089         if (rtlight->static_numlighttrispvsbytes)
3090                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3091                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3092                                 lighttris++;
3093
3094         shadowtris = 0;
3095         if (rtlight->static_numlighttrispvsbytes)
3096                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3097                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3098                                 shadowtris++;
3099
3100         if (developer_extra.integer)
3101                 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);
3102 }
3103
3104 void R_RTLight_Uncompile(rtlight_t *rtlight)
3105 {
3106         if (rtlight->compiled)
3107         {
3108                 if (rtlight->static_meshchain_shadow_zpass)
3109                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3110                 rtlight->static_meshchain_shadow_zpass = NULL;
3111                 if (rtlight->static_meshchain_shadow_zfail)
3112                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3113                 rtlight->static_meshchain_shadow_zfail = NULL;
3114                 if (rtlight->static_meshchain_shadow_shadowmap)
3115                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3116                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3117                 // these allocations are grouped
3118                 if (rtlight->static_surfacelist)
3119                         Mem_Free(rtlight->static_surfacelist);
3120                 rtlight->static_numleafs = 0;
3121                 rtlight->static_numleafpvsbytes = 0;
3122                 rtlight->static_leaflist = NULL;
3123                 rtlight->static_leafpvs = NULL;
3124                 rtlight->static_numsurfaces = 0;
3125                 rtlight->static_surfacelist = NULL;
3126                 rtlight->static_numshadowtrispvsbytes = 0;
3127                 rtlight->static_shadowtrispvs = NULL;
3128                 rtlight->static_numlighttrispvsbytes = 0;
3129                 rtlight->static_lighttrispvs = NULL;
3130                 rtlight->compiled = false;
3131         }
3132 }
3133
3134 void R_Shadow_UncompileWorldLights(void)
3135 {
3136         size_t lightindex;
3137         dlight_t *light;
3138         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3139         for (lightindex = 0;lightindex < range;lightindex++)
3140         {
3141                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3142                 if (!light)
3143                         continue;
3144                 R_RTLight_Uncompile(&light->rtlight);
3145         }
3146 }
3147
3148 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3149 {
3150         int i, j;
3151         mplane_t plane;
3152         // reset the count of frustum planes
3153         // see rtlight->cached_frustumplanes definition for how much this array
3154         // can hold
3155         rtlight->cached_numfrustumplanes = 0;
3156
3157         // haven't implemented a culling path for ortho rendering
3158         if (!r_refdef.view.useperspective)
3159         {
3160                 // check if the light is on screen and copy the 4 planes if it is
3161                 for (i = 0;i < 4;i++)
3162                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3163                                 break;
3164                 if (i == 4)
3165                         for (i = 0;i < 4;i++)
3166                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3167                 return;
3168         }
3169
3170 #if 1
3171         // generate a deformed frustum that includes the light origin, this is
3172         // used to cull shadow casting surfaces that can not possibly cast a
3173         // shadow onto the visible light-receiving surfaces, which can be a
3174         // performance gain
3175         //
3176         // if the light origin is onscreen the result will be 4 planes exactly
3177         // if the light origin is offscreen on only one axis the result will
3178         // be exactly 5 planes (split-side case)
3179         // if the light origin is offscreen on two axes the result will be
3180         // exactly 4 planes (stretched corner case)
3181         for (i = 0;i < 4;i++)
3182         {
3183                 // quickly reject standard frustum planes that put the light
3184                 // origin outside the frustum
3185                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3186                         continue;
3187                 // copy the plane
3188                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3189         }
3190         // if all the standard frustum planes were accepted, the light is onscreen
3191         // otherwise we need to generate some more planes below...
3192         if (rtlight->cached_numfrustumplanes < 4)
3193         {
3194                 // at least one of the stock frustum planes failed, so we need to
3195                 // create one or two custom planes to enclose the light origin
3196                 for (i = 0;i < 4;i++)
3197                 {
3198                         // create a plane using the view origin and light origin, and a
3199                         // single point from the frustum corner set
3200                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3201                         VectorNormalize(plane.normal);
3202                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3203                         // see if this plane is backwards and flip it if so
3204                         for (j = 0;j < 4;j++)
3205                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3206                                         break;
3207                         if (j < 4)
3208                         {
3209                                 VectorNegate(plane.normal, plane.normal);
3210                                 plane.dist *= -1;
3211                                 // flipped plane, test again to see if it is now valid
3212                                 for (j = 0;j < 4;j++)
3213                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3214                                                 break;
3215                                 // if the plane is still not valid, then it is dividing the
3216                                 // frustum and has to be rejected
3217                                 if (j < 4)
3218                                         continue;
3219                         }
3220                         // we have created a valid plane, compute extra info
3221                         PlaneClassify(&plane);
3222                         // copy the plane
3223                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3224 #if 1
3225                         // if we've found 5 frustum planes then we have constructed a
3226                         // proper split-side case and do not need to keep searching for
3227                         // planes to enclose the light origin
3228                         if (rtlight->cached_numfrustumplanes == 5)
3229                                 break;
3230 #endif
3231                 }
3232         }
3233 #endif
3234
3235 #if 0
3236         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3237         {
3238                 plane = rtlight->cached_frustumplanes[i];
3239                 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));
3240         }
3241 #endif
3242
3243 #if 0
3244         // now add the light-space box planes if the light box is rotated, as any
3245         // caster outside the oriented light box is irrelevant (even if it passed
3246         // the worldspace light box, which is axial)
3247         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3248         {
3249                 for (i = 0;i < 6;i++)
3250                 {
3251                         vec3_t v;
3252                         VectorClear(v);
3253                         v[i >> 1] = (i & 1) ? -1 : 1;
3254                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3255                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3256                         plane.dist = VectorNormalizeLength(plane.normal);
3257                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3258                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3259                 }
3260         }
3261 #endif
3262
3263 #if 0
3264         // add the world-space reduced box planes
3265         for (i = 0;i < 6;i++)
3266         {
3267                 VectorClear(plane.normal);
3268                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3269                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3270                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3271         }
3272 #endif
3273
3274 #if 0
3275         {
3276         int j, oldnum;
3277         vec3_t points[8];
3278         vec_t bestdist;
3279         // reduce all plane distances to tightly fit the rtlight cull box, which
3280         // is in worldspace
3281         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3282         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3283         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3284         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3285         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3286         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3287         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3288         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3289         oldnum = rtlight->cached_numfrustumplanes;
3290         rtlight->cached_numfrustumplanes = 0;
3291         for (j = 0;j < oldnum;j++)
3292         {
3293                 // find the nearest point on the box to this plane
3294                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3295                 for (i = 1;i < 8;i++)
3296                 {
3297                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3298                         if (bestdist > dist)
3299                                 bestdist = dist;
3300                 }
3301                 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);
3302                 // if the nearest point is near or behind the plane, we want this
3303                 // plane, otherwise the plane is useless as it won't cull anything
3304                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3305                 {
3306                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3307                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3308                 }
3309         }
3310         }
3311 #endif
3312 }
3313
3314 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3315 {
3316         shadowmesh_t *mesh;
3317
3318         RSurf_ActiveWorldEntity();
3319
3320         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3321         {
3322                 CHECKGLERROR
3323                 GL_CullFace(GL_NONE);
3324         mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3325         for (;mesh;mesh = mesh->next)
3326         {
3327                         if (!mesh->sidetotals[r_shadow_shadowmapside])
3328                                 continue;
3329             r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3330             R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3331             R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3332         }
3333         CHECKGLERROR
3334     }
3335         else if (r_refdef.scene.worldentity->model)
3336                 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);
3337
3338         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3339 }
3340
3341 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3342 {
3343         qboolean zpass = false;
3344         shadowmesh_t *mesh;
3345         int t, tend;
3346         int surfacelistindex;
3347         msurface_t *surface;
3348
3349         RSurf_ActiveWorldEntity();
3350
3351         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3352         {
3353                 CHECKGLERROR
3354                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3355                 {
3356                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3357                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3358                 }
3359                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3360                 for (;mesh;mesh = mesh->next)
3361                 {
3362                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3363                         R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3364                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3365                         {
3366                                 // increment stencil if frontface is infront of depthbuffer
3367                                 GL_CullFace(r_refdef.view.cullface_back);
3368                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3369                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3370                                 // decrement stencil if backface is infront of depthbuffer
3371                                 GL_CullFace(r_refdef.view.cullface_front);
3372                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3373                         }
3374                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3375                         {
3376                                 // decrement stencil if backface is behind depthbuffer
3377                                 GL_CullFace(r_refdef.view.cullface_front);
3378                                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3379                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3380                                 // increment stencil if frontface is behind depthbuffer
3381                                 GL_CullFace(r_refdef.view.cullface_back);
3382                                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3383                         }
3384                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3385                 }
3386                 CHECKGLERROR
3387         }
3388         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3389         {
3390                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3391                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3392                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3393                 {
3394                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3395                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3396                                 if (CHECKPVSBIT(trispvs, t))
3397                                         shadowmarklist[numshadowmark++] = t;
3398                 }
3399                 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);
3400         }
3401         else if (numsurfaces)
3402                 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);
3403
3404         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3405 }
3406
3407 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3408 {
3409         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3410         vec_t relativeshadowradius;
3411         RSurf_ActiveModelEntity(ent, false, false, false);
3412         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3413         // we need to re-init the shader for each entity because the matrix changed
3414         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3415         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3416         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3417         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3418         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3419         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3420         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3421         switch (r_shadow_rendermode)
3422         {
3423         case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3424         case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
3425         case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
3426                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3427                 break;
3428         default:
3429                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3430                 break;
3431         }
3432         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3433 }
3434
3435 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3436 {
3437         // set up properties for rendering light onto this entity
3438         RSurf_ActiveModelEntity(ent, true, true, false);
3439         GL_AlphaTest(false);
3440         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3441         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3442         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3443         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3444 }
3445
3446 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3447 {
3448         if (!r_refdef.scene.worldmodel->DrawLight)
3449                 return;
3450
3451         // set up properties for rendering light onto this entity
3452         RSurf_ActiveWorldEntity();
3453         GL_AlphaTest(false);
3454         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3455         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3456         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3457         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3458
3459         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3460
3461         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3462 }
3463
3464 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3465 {
3466         dp_model_t *model = ent->model;
3467         if (!model->DrawLight)
3468                 return;
3469
3470         R_Shadow_SetupEntityLight(ent);
3471
3472         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3473
3474         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3475 }
3476
3477 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3478 {
3479         int i;
3480         float f;
3481         int numleafs, numsurfaces;
3482         int *leaflist, *surfacelist;
3483         unsigned char *leafpvs;
3484         unsigned char *shadowtrispvs;
3485         unsigned char *lighttrispvs;
3486         //unsigned char *surfacesides;
3487         int numlightentities;
3488         int numlightentities_noselfshadow;
3489         int numshadowentities;
3490         int numshadowentities_noselfshadow;
3491         static entity_render_t *lightentities[MAX_EDICTS];
3492         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3493         static entity_render_t *shadowentities[MAX_EDICTS];
3494         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3495         qboolean nolight;
3496
3497         rtlight->draw = false;
3498
3499         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3500         // skip lights that are basically invisible (color 0 0 0)
3501         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3502
3503         // loading is done before visibility checks because loading should happen
3504         // all at once at the start of a level, not when it stalls gameplay.
3505         // (especially important to benchmarks)
3506         // compile light
3507         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3508         {
3509                 if (rtlight->compiled)
3510                         R_RTLight_Uncompile(rtlight);
3511                 R_RTLight_Compile(rtlight);
3512         }
3513
3514         // load cubemap
3515         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3516
3517         // look up the light style value at this time
3518         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3519         VectorScale(rtlight->color, f, rtlight->currentcolor);
3520         /*
3521         if (rtlight->selected)
3522         {
3523                 f = 2 + sin(realtime * M_PI * 4.0);
3524                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3525         }
3526         */
3527
3528         // if lightstyle is currently off, don't draw the light
3529         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3530                 return;
3531
3532         // skip processing on corona-only lights
3533         if (nolight)
3534                 return;
3535
3536         // if the light box is offscreen, skip it
3537         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3538                 return;
3539
3540         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3541         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3542
3543         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3544
3545         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3546         {
3547                 // compiled light, world available and can receive realtime lighting
3548                 // retrieve leaf information
3549                 numleafs = rtlight->static_numleafs;
3550                 leaflist = rtlight->static_leaflist;
3551                 leafpvs = rtlight->static_leafpvs;
3552                 numsurfaces = rtlight->static_numsurfaces;
3553                 surfacelist = rtlight->static_surfacelist;
3554                 //surfacesides = NULL;
3555                 shadowtrispvs = rtlight->static_shadowtrispvs;
3556                 lighttrispvs = rtlight->static_lighttrispvs;
3557         }
3558         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3559         {
3560                 // dynamic light, world available and can receive realtime lighting
3561                 // calculate lit surfaces and leafs
3562                 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);
3563                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3564                 leaflist = r_shadow_buffer_leaflist;
3565                 leafpvs = r_shadow_buffer_leafpvs;
3566                 surfacelist = r_shadow_buffer_surfacelist;
3567                 //surfacesides = r_shadow_buffer_surfacesides;
3568                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3569                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3570                 // if the reduced leaf bounds are offscreen, skip it
3571                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3572                         return;
3573         }
3574         else
3575         {
3576                 // no world
3577                 numleafs = 0;
3578                 leaflist = NULL;
3579                 leafpvs = NULL;
3580                 numsurfaces = 0;
3581                 surfacelist = NULL;
3582                 //surfacesides = NULL;
3583                 shadowtrispvs = NULL;
3584                 lighttrispvs = NULL;
3585         }
3586         // check if light is illuminating any visible leafs
3587         if (numleafs)
3588         {
3589                 for (i = 0;i < numleafs;i++)
3590                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3591                                 break;
3592                 if (i == numleafs)
3593                         return;
3594         }
3595
3596         // make a list of lit entities and shadow casting entities
3597         numlightentities = 0;
3598         numlightentities_noselfshadow = 0;
3599         numshadowentities = 0;
3600         numshadowentities_noselfshadow = 0;
3601
3602         // add dynamic entities that are lit by the light
3603         for (i = 0;i < r_refdef.scene.numentities;i++)
3604         {
3605                 dp_model_t *model;
3606                 entity_render_t *ent = r_refdef.scene.entities[i];
3607                 vec3_t org;
3608                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3609                         continue;
3610                 // skip the object entirely if it is not within the valid
3611                 // shadow-casting region (which includes the lit region)
3612                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3613                         continue;
3614                 if (!(model = ent->model))
3615                         continue;
3616                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3617                 {
3618                         // this entity wants to receive light, is visible, and is
3619                         // inside the light box
3620                         // TODO: check if the surfaces in the model can receive light
3621                         // so now check if it's in a leaf seen by the light
3622                         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))
3623                                 continue;
3624                         if (ent->flags & RENDER_NOSELFSHADOW)
3625                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3626                         else
3627                                 lightentities[numlightentities++] = ent;
3628                         // since it is lit, it probably also casts a shadow...
3629                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3630                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3631                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3632                         {
3633                                 // note: exterior models without the RENDER_NOSELFSHADOW
3634                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3635                                 // are lit normally, this means that they are
3636                                 // self-shadowing but do not shadow other
3637                                 // RENDER_NOSELFSHADOW entities such as the gun
3638                                 // (very weird, but keeps the player shadow off the gun)
3639                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3640                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3641                                 else
3642                                         shadowentities[numshadowentities++] = ent;
3643                         }
3644                 }
3645                 else if (ent->flags & RENDER_SHADOW)
3646                 {
3647                         // this entity is not receiving light, but may still need to
3648                         // cast a shadow...
3649                         // TODO: check if the surfaces in the model can cast shadow
3650                         // now check if it is in a leaf seen by the light
3651                         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))
3652                                 continue;
3653                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3654                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3655                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3656                         {
3657                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3658                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3659                                 else
3660                                         shadowentities[numshadowentities++] = ent;
3661                         }
3662                 }
3663         }
3664
3665         // return if there's nothing at all to light
3666         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3667                 return;
3668
3669         // count this light in the r_speeds
3670         r_refdef.stats.lights++;
3671
3672         // flag it as worth drawing later
3673         rtlight->draw = true;
3674
3675         // cache all the animated entities that cast a shadow but are not visible
3676         for (i = 0;i < numshadowentities;i++)
3677                 if (!shadowentities[i]->animcache_vertex3f)
3678                         R_AnimCache_GetEntity(shadowentities[i], false, false);
3679         for (i = 0;i < numshadowentities_noselfshadow;i++)
3680                 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3681                         R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3682
3683         // allocate some temporary memory for rendering this light later in the frame
3684         // reusable buffers need to be copied, static data can be used as-is
3685         rtlight->cached_numlightentities               = numlightentities;
3686         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
3687         rtlight->cached_numshadowentities              = numshadowentities;
3688         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3689         rtlight->cached_numsurfaces                    = numsurfaces;
3690         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3691         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3692         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3693         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3694         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3695         {
3696                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3697                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3698                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3699                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3700                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3701         }
3702         else
3703         {
3704                 // compiled light data
3705                 rtlight->cached_shadowtrispvs = shadowtrispvs;
3706                 rtlight->cached_lighttrispvs = lighttrispvs;
3707                 rtlight->cached_surfacelist = surfacelist;
3708         }
3709 }
3710
3711 void R_Shadow_DrawLight(rtlight_t *rtlight)
3712 {
3713         int i;
3714         int numsurfaces;
3715         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3716         int numlightentities;
3717         int numlightentities_noselfshadow;
3718         int numshadowentities;
3719         int numshadowentities_noselfshadow;
3720         entity_render_t **lightentities;
3721         entity_render_t **lightentities_noselfshadow;
3722         entity_render_t **shadowentities;
3723         entity_render_t **shadowentities_noselfshadow;
3724         int *surfacelist;
3725         static unsigned char entitysides[MAX_EDICTS];
3726         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3727         vec3_t nearestpoint;
3728         vec_t distance;
3729         qboolean castshadows;
3730         int lodlinear;
3731
3732         // check if we cached this light this frame (meaning it is worth drawing)
3733         if (!rtlight->draw)
3734                 return;
3735
3736         // if R_FrameData_Store ran out of space we skip anything dependent on it
3737         if (r_framedata_failed)
3738                 return;
3739
3740         numlightentities = rtlight->cached_numlightentities;
3741         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3742         numshadowentities = rtlight->cached_numshadowentities;
3743         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3744         numsurfaces = rtlight->cached_numsurfaces;
3745         lightentities = rtlight->cached_lightentities;
3746         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3747         shadowentities = rtlight->cached_shadowentities;
3748         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3749         shadowtrispvs = rtlight->cached_shadowtrispvs;
3750         lighttrispvs = rtlight->cached_lighttrispvs;
3751         surfacelist = rtlight->cached_surfacelist;
3752
3753         // set up a scissor rectangle for this light
3754         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3755                 return;
3756
3757         // don't let sound skip if going slow
3758         if (r_refdef.scene.extraupdate)
3759                 S_ExtraUpdate ();
3760
3761         // make this the active rtlight for rendering purposes
3762         R_Shadow_RenderMode_ActiveLight(rtlight);
3763
3764         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3765         {
3766                 // optionally draw visible shape of the shadow volumes
3767                 // for performance analysis by level designers
3768                 R_Shadow_RenderMode_VisibleShadowVolumes();
3769                 if (numsurfaces)
3770                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3771                 for (i = 0;i < numshadowentities;i++)
3772                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3773                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3774                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3775                 R_Shadow_RenderMode_VisibleLighting(false, false);
3776         }
3777
3778         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3779         {
3780                 // optionally draw the illuminated areas
3781                 // for performance analysis by level designers
3782                 R_Shadow_RenderMode_VisibleLighting(false, false);
3783                 if (numsurfaces)
3784                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3785                 for (i = 0;i < numlightentities;i++)
3786                         R_Shadow_DrawEntityLight(lightentities[i]);
3787                 for (i = 0;i < numlightentities_noselfshadow;i++)
3788                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3789         }
3790
3791         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3792
3793         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3794         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3795         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3796         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3797
3798         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3799         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3800         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3801
3802         if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3803         {
3804                 float borderbias;
3805                 int side;
3806                 int size;
3807                 int castermask = 0;
3808                 int receivermask = 0;
3809                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3810                 Matrix4x4_Abs(&radiustolight);
3811
3812                 r_shadow_shadowmaplod = 0;
3813                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3814                         if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3815                                 r_shadow_shadowmaplod = i;
3816
3817                 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3818                         size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3819                 else
3820                         size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3821                         
3822                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3823
3824                 surfacesides = NULL;
3825                 if (numsurfaces)
3826                 {
3827                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3828                         {
3829                                 castermask = rtlight->static_shadowmap_casters;
3830                                 receivermask = rtlight->static_shadowmap_receivers;
3831                         }
3832                         else
3833                         {
3834                                 surfacesides = r_shadow_buffer_surfacesides;
3835                                 for(i = 0;i < numsurfaces;i++)
3836                                 {
3837                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3838                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
3839                                         castermask |= surfacesides[i];
3840                                         receivermask |= surfacesides[i];
3841                                 }
3842                         }
3843                 }
3844                 if (receivermask < 0x3F) 
3845                 {
3846                         for (i = 0;i < numlightentities;i++)
3847                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3848                         if (receivermask < 0x3F)
3849                                 for(i = 0; i < numlightentities_noselfshadow;i++)
3850                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3851                 }
3852
3853                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3854
3855                 if (receivermask)
3856                 {
3857                         for (i = 0;i < numshadowentities;i++)
3858                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3859                         for (i = 0;i < numshadowentities_noselfshadow;i++)
3860                                 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
3861                 }
3862
3863                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3864
3865                 // render shadow casters into 6 sided depth texture
3866                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3867                 {
3868                         R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3869                         if (! (castermask & (1 << side))) continue;
3870                         if (numsurfaces)
3871                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3872                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3873                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3874                 }
3875
3876                 if (numlightentities_noselfshadow)
3877                 {
3878                         // render lighting using the depth texture as shadowmap
3879                         // draw lighting in the unmasked areas
3880                         R_Shadow_RenderMode_Lighting(false, false, true);
3881                         for (i = 0;i < numlightentities_noselfshadow;i++)
3882                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3883                 }
3884
3885                 // render shadow casters into 6 sided depth texture
3886                 if (numshadowentities_noselfshadow)
3887                 {
3888                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3889                         {
3890                                 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3891                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3892                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3893                         }
3894                 }
3895
3896                 // render lighting using the depth texture as shadowmap
3897                 // draw lighting in the unmasked areas
3898                 R_Shadow_RenderMode_Lighting(false, false, true);
3899                 // draw lighting in the unmasked areas
3900                 if (numsurfaces)
3901                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3902                 for (i = 0;i < numlightentities;i++)
3903                         R_Shadow_DrawEntityLight(lightentities[i]);
3904         }
3905         else if (castshadows && vid.stencil)
3906         {
3907                 // draw stencil shadow volumes to mask off pixels that are in shadow
3908                 // so that they won't receive lighting
3909                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3910                 R_Shadow_ClearStencil();
3911
3912                 if (numsurfaces)
3913                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3914                 for (i = 0;i < numshadowentities;i++)
3915                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3916
3917                 // draw lighting in the unmasked areas
3918                 R_Shadow_RenderMode_Lighting(true, false, false);
3919                 for (i = 0;i < numlightentities_noselfshadow;i++)
3920                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3921
3922                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3923                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3924
3925                 // draw lighting in the unmasked areas
3926                 R_Shadow_RenderMode_Lighting(true, false, false);
3927                 if (numsurfaces)
3928                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3929                 for (i = 0;i < numlightentities;i++)
3930                         R_Shadow_DrawEntityLight(lightentities[i]);
3931         }
3932         else
3933         {
3934                 // draw lighting in the unmasked areas
3935                 R_Shadow_RenderMode_Lighting(false, false, false);
3936                 if (numsurfaces)
3937                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3938                 for (i = 0;i < numlightentities;i++)
3939                         R_Shadow_DrawEntityLight(lightentities[i]);
3940                 for (i = 0;i < numlightentities_noselfshadow;i++)
3941                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3942         }
3943
3944         if (r_shadow_usingdeferredprepass)
3945         {
3946                 // when rendering deferred lighting, we simply rasterize the box
3947                 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3948                         R_Shadow_RenderMode_DrawDeferredLight(false, true);
3949                 else if (castshadows && vid.stencil)
3950                         R_Shadow_RenderMode_DrawDeferredLight(true, false);
3951                 else
3952                         R_Shadow_RenderMode_DrawDeferredLight(false, false);
3953         }
3954 }
3955
3956 static void R_Shadow_FreeDeferred(void)
3957 {
3958         if (r_shadow_prepassgeometryfbo)
3959                 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3960         r_shadow_prepassgeometryfbo = 0;
3961
3962         if (r_shadow_prepasslightingfbo)
3963                 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3964         r_shadow_prepasslightingfbo = 0;
3965
3966         if (r_shadow_prepassgeometrydepthtexture)
3967                 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3968         r_shadow_prepassgeometrydepthtexture = NULL;
3969
3970         if (r_shadow_prepassgeometrynormalmaptexture)
3971                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3972         r_shadow_prepassgeometrynormalmaptexture = NULL;
3973
3974         if (r_shadow_prepasslightingdiffusetexture)
3975                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3976         r_shadow_prepasslightingdiffusetexture = NULL;
3977
3978         if (r_shadow_prepasslightingspeculartexture)
3979                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3980         r_shadow_prepasslightingspeculartexture = NULL;
3981 }
3982
3983 void R_Shadow_DrawPrepass(void)
3984 {
3985         int i;
3986         int flag;
3987         int lnum;
3988         size_t lightindex;
3989         dlight_t *light;
3990         size_t range;
3991         entity_render_t *ent;
3992
3993         GL_AlphaTest(false);
3994         R_Mesh_ColorPointer(NULL, 0, 0);
3995         R_Mesh_ResetTextureState();
3996         GL_DepthMask(true);
3997         GL_ColorMask(1,1,1,1);
3998         GL_BlendFunc(GL_ONE, GL_ZERO);
3999         GL_Color(1,1,1,1);
4000         GL_DepthTest(true);
4001         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4002         qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
4003         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
4004
4005         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4006                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4007         if (r_timereport_active)
4008                 R_TimeReport("prepassworld");
4009
4010         for (i = 0;i < r_refdef.scene.numentities;i++)
4011         {
4012                 if (!r_refdef.viewcache.entityvisible[i])
4013                         continue;
4014                 ent = r_refdef.scene.entities[i];
4015                 if (ent->model && ent->model->DrawPrepass != NULL)
4016                         ent->model->DrawPrepass(ent);
4017         }
4018
4019         if (r_timereport_active)
4020                 R_TimeReport("prepassmodels");
4021
4022         GL_DepthMask(false);
4023         GL_ColorMask(1,1,1,1);
4024         GL_Color(1,1,1,1);
4025         GL_DepthTest(true);
4026         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4027         qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
4028         GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
4029         if (r_refdef.fogenabled)
4030                 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4031
4032         R_Shadow_RenderMode_Begin();
4033
4034         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4035         if (r_shadow_debuglight.integer >= 0)
4036         {
4037                 lightindex = r_shadow_debuglight.integer;
4038                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4039                 if (light && (light->flags & flag))
4040                         R_Shadow_DrawLight(&light->rtlight);
4041         }
4042         else
4043         {
4044                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4045                 for (lightindex = 0;lightindex < range;lightindex++)
4046                 {
4047                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4048                         if (light && (light->flags & flag))
4049                                 R_Shadow_DrawLight(&light->rtlight);
4050                 }
4051         }
4052         if (r_refdef.scene.rtdlight)
4053                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4054                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4055
4056         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4057         if (r_refdef.fogenabled)
4058                 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4059
4060         R_Shadow_RenderMode_End();
4061
4062         if (r_timereport_active)
4063                 R_TimeReport("prepasslights");
4064 }
4065
4066 void R_Shadow_DrawLightSprites(void);
4067 void R_Shadow_PrepareLights(void)
4068 {
4069         int flag;
4070         int lnum;
4071         size_t lightindex;
4072         dlight_t *light;
4073         size_t range;
4074         float f;
4075         GLenum status;
4076
4077         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4078                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4079                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || 
4080                 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4081                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4082                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4083                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4084                 R_Shadow_FreeShadowMaps();
4085
4086         r_shadow_usingshadowmaportho = false;
4087
4088         switch (vid.renderpath)
4089         {
4090         case RENDERPATH_GL20:
4091         case RENDERPATH_CGGL:
4092                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4093                 {
4094                         r_shadow_usingdeferredprepass = false;
4095                         if (r_shadow_prepass_width)
4096                                 R_Shadow_FreeDeferred();
4097                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4098                         break;
4099                 }
4100
4101                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4102                 {
4103                         R_Shadow_FreeDeferred();
4104
4105                         r_shadow_usingdeferredprepass = true;
4106                         r_shadow_prepass_width = vid.width;
4107                         r_shadow_prepass_height = vid.height;
4108                         r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4109                         r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4110                         r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4111                         r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4112
4113                         // set up the geometry pass fbo (depth + normalmap)
4114                         qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4115                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4116                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4117                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4118                         // render depth into one texture and normalmap into the other
4119                         if (qglDrawBuffersARB)
4120                         {
4121                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4122                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4123                         }
4124                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4125                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4126                         {
4127                                 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4128                                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4129                                 r_shadow_usingdeferredprepass = false;
4130                         }
4131
4132                         // set up the lighting pass fbo (diffuse + specular)
4133                         qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4134                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4135                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4136                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4137                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4138                         // render diffuse into one texture and specular into another,
4139                         // with depth and normalmap bound as textures,
4140                         // with depth bound as attachment as well
4141                         if (qglDrawBuffersARB)
4142                         {
4143                                 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4144                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4145                         }
4146                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4147                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4148                         {
4149                                 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4150                                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4151                                 r_shadow_usingdeferredprepass = false;
4152                         }
4153                 }
4154                 break;
4155         case RENDERPATH_GL13:
4156         case RENDERPATH_GL11:
4157                 r_shadow_usingdeferredprepass = false;
4158                 break;
4159         }
4160
4161         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);
4162
4163         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4164         if (r_shadow_debuglight.integer >= 0)
4165         {
4166                 lightindex = r_shadow_debuglight.integer;
4167                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4168                 if (light && (light->flags & flag))
4169                         R_Shadow_PrepareLight(&light->rtlight);
4170         }
4171         else
4172         {
4173                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4174                 for (lightindex = 0;lightindex < range;lightindex++)
4175                 {
4176                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4177                         if (light && (light->flags & flag))
4178                                 R_Shadow_PrepareLight(&light->rtlight);
4179                 }
4180         }
4181         if (r_refdef.scene.rtdlight)
4182         {
4183                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4184                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4185         }
4186         else if(gl_flashblend.integer)
4187         {
4188                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4189                 {
4190                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4191                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4192                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4193                 }
4194         }
4195
4196         if (r_editlights.integer)
4197                 R_Shadow_DrawLightSprites();
4198 }
4199
4200 void R_Shadow_DrawLights(void)
4201 {
4202         int flag;
4203         int lnum;
4204         size_t lightindex;
4205         dlight_t *light;
4206         size_t range;
4207
4208         R_Shadow_RenderMode_Begin();
4209
4210         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4211         if (r_shadow_debuglight.integer >= 0)
4212         {
4213                 lightindex = r_shadow_debuglight.integer;
4214                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4215                 if (light && (light->flags & flag))
4216                         R_Shadow_DrawLight(&light->rtlight);
4217         }
4218         else
4219         {
4220                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4221                 for (lightindex = 0;lightindex < range;lightindex++)
4222                 {
4223                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4224                         if (light && (light->flags & flag))
4225                                 R_Shadow_DrawLight(&light->rtlight);
4226                 }
4227         }
4228         if (r_refdef.scene.rtdlight)
4229                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4230                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4231
4232         R_Shadow_RenderMode_End();
4233 }
4234
4235 extern const float r_screenvertex3f[12];
4236 extern void R_SetupView(qboolean allowwaterclippingplane);
4237 extern void R_ResetViewRendering3D(void);
4238 extern void R_ResetViewRendering2D(void);
4239 extern cvar_t r_shadows;
4240 extern cvar_t r_shadows_darken;
4241 extern cvar_t r_shadows_drawafterrtlighting;
4242 extern cvar_t r_shadows_castfrombmodels;
4243 extern cvar_t r_shadows_throwdistance;
4244 extern cvar_t r_shadows_throwdirection;
4245 extern cvar_t r_shadows_focus;
4246 extern cvar_t r_shadows_shadowmapscale;
4247
4248 void R_Shadow_PrepareModelShadows(void)
4249 {
4250         int i;
4251         float scale, size, radius, dot1, dot2;
4252         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4253         entity_render_t *ent;
4254
4255         if (!r_refdef.scene.numentities)
4256                 return;
4257
4258         switch (r_shadow_shadowmode)
4259         {
4260         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4261         case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4262                 if (r_shadows.integer >= 2) 
4263                         break;
4264                 // fall through
4265         case R_SHADOW_SHADOWMODE_STENCIL:
4266                 for (i = 0;i < r_refdef.scene.numentities;i++)
4267                 {
4268                         ent = r_refdef.scene.entities[i];
4269                         if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4270                                 R_AnimCache_GetEntity(ent, false, false);
4271                 }
4272                 return;
4273         default:
4274                 return;
4275         }
4276
4277         size = 2*r_shadow_shadowmapmaxsize;
4278         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4279         radius = 0.5f * size / scale;
4280
4281         Math_atov(r_shadows_throwdirection.string, shadowdir);
4282         VectorNormalize(shadowdir);
4283         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4284         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4285         if (fabs(dot1) <= fabs(dot2))
4286                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4287         else
4288                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4289         VectorNormalize(shadowforward);
4290         CrossProduct(shadowdir, shadowforward, shadowright);
4291         Math_atov(r_shadows_focus.string, shadowfocus);
4292         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4293         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4294         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4295         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4296         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4297                 dot1 = 1;
4298         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4299
4300         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4301         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4302         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4303         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4304         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4305         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4306
4307         for (i = 0;i < r_refdef.scene.numentities;i++)
4308         {
4309                 ent = r_refdef.scene.entities[i];
4310                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4311                         continue;
4312                 // cast shadows from anything of the map (submodels are optional)
4313                 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4314                         R_AnimCache_GetEntity(ent, false, false);
4315         }
4316 }
4317
4318 void R_DrawModelShadowMaps(void)
4319 {
4320         int i;
4321         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4322         entity_render_t *ent;
4323         vec3_t relativelightorigin;
4324         vec3_t relativelightdirection, relativeforward, relativeright;
4325         vec3_t relativeshadowmins, relativeshadowmaxs;
4326         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4327         float m[12];
4328         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4329         r_viewport_t viewport;
4330         GLuint fbo = 0;
4331
4332         if (!r_refdef.scene.numentities)
4333                 return;
4334
4335         switch (r_shadow_shadowmode)
4336         {
4337         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4338         case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4339                 break;
4340         default:
4341                 return;
4342         }
4343
4344         CHECKGLERROR
4345         R_ResetViewRendering3D();
4346         R_Shadow_RenderMode_Begin();
4347         R_Shadow_RenderMode_ActiveLight(NULL);
4348
4349         switch (r_shadow_shadowmode)
4350         {
4351         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4352                 if (!r_shadow_shadowmap2dtexture)
4353                         R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4354                 fbo = r_shadow_fbo2d;
4355                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4356                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4357                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4358                 break;
4359         case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4360                 if (!r_shadow_shadowmaprectangletexture)
4361                         R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4362                 fbo = r_shadow_fborectangle;
4363                 r_shadow_shadowmap_texturescale[0] = 1.0f;
4364                 r_shadow_shadowmap_texturescale[1] = 1.0f;
4365                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4366                 break;
4367         default:
4368                 break;
4369         }
4370
4371         size = 2*r_shadow_shadowmapmaxsize;
4372         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4373         radius = 0.5f / scale;
4374         nearclip = -r_shadows_throwdistance.value;
4375         farclip = r_shadows_throwdistance.value;
4376         bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4377
4378         r_shadow_shadowmap_parameters[0] = size;
4379         r_shadow_shadowmap_parameters[1] = size;
4380         r_shadow_shadowmap_parameters[2] = 1.0;
4381         r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4382
4383         Math_atov(r_shadows_throwdirection.string, shadowdir);
4384         VectorNormalize(shadowdir);
4385         Math_atov(r_shadows_focus.string, shadowfocus);
4386         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4387         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4388         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4389         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4390         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4391         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4392         if (fabs(dot1) <= fabs(dot2)) 
4393                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4394         else
4395                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4396         VectorNormalize(shadowforward);
4397         VectorM(scale, shadowforward, &m[0]);
4398         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4399                 dot1 = 1;
4400         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4401         CrossProduct(shadowdir, shadowforward, shadowright);
4402         VectorM(scale, shadowright, &m[4]);
4403         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4404         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4405         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4406         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4407         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4408         R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
4409
4410         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4411  
4412 #if 0
4413         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4414         R_SetupShader_ShowDepth();
4415 #else
4416         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
4417         R_SetupShader_DepthOrShadow();
4418 #endif
4419         CHECKGLERROR
4420         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4421         GL_DepthMask(true);
4422         GL_DepthTest(true);
4423         R_SetViewport(&viewport);
4424         GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4425         qglClearDepth(1);
4426 #if 0
4427         qglClearColor(1,1,1,1);
4428         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4429 #else
4430         GL_Clear(GL_DEPTH_BUFFER_BIT);
4431 #endif
4432         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4433         CHECKGLERROR
4434
4435         for (i = 0;i < r_refdef.scene.numentities;i++)
4436         {
4437                 ent = r_refdef.scene.entities[i];
4438
4439                 // cast shadows from anything of the map (submodels are optional)
4440                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4441                 {
4442                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4443                         Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4444                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4445                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4446                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4447                         relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4448                         relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4449                         relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4450                         relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4451                         relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4452                         relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4453                         RSurf_ActiveModelEntity(ent, false, false, false);
4454                         ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4455                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4456                 }
4457         }
4458
4459         R_Shadow_RenderMode_End();
4460
4461         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4462         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4463         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
4464         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4465         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4466         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4467
4468         r_shadow_usingshadowmaportho = true;
4469         switch (r_shadow_shadowmode)
4470         {
4471         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4472                 r_shadow_usingshadowmap2d = true;
4473                 break;
4474         case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4475                 r_shadow_usingshadowmaprect = true;
4476                 break;
4477         default:
4478                 break;
4479         }
4480 }
4481
4482 void R_DrawModelShadows(void)
4483 {
4484         int i;
4485         float relativethrowdistance;
4486         entity_render_t *ent;
4487         vec3_t relativelightorigin;
4488         vec3_t relativelightdirection;
4489         vec3_t relativeshadowmins, relativeshadowmaxs;
4490         vec3_t tmp, shadowdir;
4491
4492         if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4493                 return;
4494
4495         CHECKGLERROR
4496         R_ResetViewRendering3D();
4497         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4498         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4499         R_Shadow_RenderMode_Begin();
4500         R_Shadow_RenderMode_ActiveLight(NULL);
4501         r_shadow_lightscissor[0] = r_refdef.view.x;
4502         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4503         r_shadow_lightscissor[2] = r_refdef.view.width;
4504         r_shadow_lightscissor[3] = r_refdef.view.height;
4505         R_Shadow_RenderMode_StencilShadowVolumes(false);
4506
4507         // get shadow dir
4508         if (r_shadows.integer == 2)
4509         {
4510                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4511                 VectorNormalize(shadowdir);
4512         }
4513
4514         R_Shadow_ClearStencil();
4515
4516         for (i = 0;i < r_refdef.scene.numentities;i++)
4517         {
4518                 ent = r_refdef.scene.entities[i];
4519
4520                 // cast shadows from anything of the map (submodels are optional)
4521                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4522                 {
4523                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4524                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4525                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4526                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4527                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4528                         else
4529                         {
4530                                 if(ent->entitynumber != 0)
4531                                 {
4532                                         if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4533                                         {
4534                                                 // FIXME handle this
4535                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4536                                         }
4537                                         else
4538                                         {
4539                                                 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4540                                                 int entnum, entnum2, recursion;
4541                                                 entnum = entnum2 = ent->entitynumber;
4542                                                 for(recursion = 32; recursion > 0; --recursion)
4543                                                 {
4544                                                         entnum2 = cl.entities[entnum].state_current.tagentity;
4545                                                         if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4546                                                                 entnum = entnum2;
4547                                                         else
4548                                                                 break;
4549                                                 }
4550                                                 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4551                                                 {
4552                                                         VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4553                                                         // transform into modelspace of OUR entity
4554                                                         Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4555                                                         Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4556                                                 }
4557                                                 else
4558                                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4559                                         }
4560                                 }
4561                                 else
4562                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4563                         }
4564
4565                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4566                         RSurf_ActiveModelEntity(ent, false, false, false);
4567                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4568                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4569                 }
4570         }
4571
4572         // not really the right mode, but this will disable any silly stencil features
4573         R_Shadow_RenderMode_End();
4574
4575         // set up ortho view for rendering this pass
4576         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4577         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4578         //GL_ScissorTest(true);
4579         //R_EntityMatrix(&identitymatrix);
4580         //R_Mesh_ResetTextureState();
4581         R_ResetViewRendering2D();
4582         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4583         R_Mesh_ColorPointer(NULL, 0, 0);
4584         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4585
4586         // set up a darkening blend on shadowed areas
4587         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4588         //GL_DepthRange(0, 1);
4589         //GL_DepthTest(false);
4590         //GL_DepthMask(false);
4591         //GL_PolygonOffset(0, 0);CHECKGLERROR
4592         GL_Color(0, 0, 0, r_shadows_darken.value);
4593         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4594         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4595         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4596         qglStencilMask(255);CHECKGLERROR
4597         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4598         qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4599
4600         // apply the blend to the shadowed areas
4601         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4602
4603         // restore the viewport
4604         R_SetViewport(&r_refdef.view.viewport);
4605
4606         // restore other state to normal
4607         //R_Shadow_RenderMode_End();
4608 }
4609
4610 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4611 {
4612         float zdist;
4613         vec3_t centerorigin;
4614         float vertex3f[12];
4615         // if it's too close, skip it
4616         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4617                 return;
4618         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4619         if (zdist < 32)
4620                 return;
4621         if (usequery && r_numqueries + 2 <= r_maxqueries)
4622         {
4623                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4624                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4625                 // 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
4626                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4627
4628                 CHECKGLERROR
4629                 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4630                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4631                 qglDepthFunc(GL_ALWAYS);
4632                 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4633                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4634                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4635                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4636                 qglDepthFunc(GL_LEQUAL);
4637                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4638                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4639                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4640                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4641                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4642                 CHECKGLERROR
4643         }
4644         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4645 }
4646
4647 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4648
4649 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4650 {
4651         vec3_t color;
4652         GLint allpixels = 0, visiblepixels = 0;
4653         // now we have to check the query result
4654         if (rtlight->corona_queryindex_visiblepixels)
4655         {
4656                 CHECKGLERROR
4657                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4658                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4659                 CHECKGLERROR
4660                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4661                 if (visiblepixels < 1 || allpixels < 1)
4662                         return;
4663                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4664                 cscale *= rtlight->corona_visibility;
4665         }
4666         else
4667         {
4668                 // FIXME: these traces should scan all render entities instead of cl.world
4669                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4670                         return;
4671         }
4672         VectorScale(rtlight->currentcolor, cscale, color);
4673         if (VectorLength(color) > (1.0f / 256.0f))
4674         {
4675                 float vertex3f[12];
4676                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4677                 if(negated)
4678                 {
4679                         VectorNegate(color, color);
4680                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4681                 }
4682                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4683                 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);
4684                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4685                 if(negated)
4686                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4687         }
4688 }
4689
4690 void R_Shadow_DrawCoronas(void)
4691 {
4692         int i, flag;
4693         qboolean usequery;
4694         size_t lightindex;
4695         dlight_t *light;
4696         rtlight_t *rtlight;
4697         size_t range;
4698         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4699                 return;
4700         if (r_waterstate.renderingscene)
4701                 return;
4702         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4703         R_EntityMatrix(&identitymatrix);
4704
4705         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4706
4707         // check occlusion of coronas
4708         // use GL_ARB_occlusion_query if available
4709         // otherwise use raytraces
4710         r_numqueries = 0;
4711         usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4712         if (usequery)
4713         {
4714                 GL_ColorMask(0,0,0,0);
4715                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4716                 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4717                 {
4718                         i = r_maxqueries;
4719                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4720                         r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4721                         CHECKGLERROR
4722                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4723                         CHECKGLERROR
4724                 }
4725                 RSurf_ActiveWorldEntity();
4726                 GL_BlendFunc(GL_ONE, GL_ZERO);
4727                 GL_CullFace(GL_NONE);
4728                 GL_DepthMask(false);
4729                 GL_DepthRange(0, 1);
4730                 GL_PolygonOffset(0, 0);
4731                 GL_DepthTest(true);
4732                 R_Mesh_ColorPointer(NULL, 0, 0);
4733                 R_Mesh_ResetTextureState();
4734                 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4735         }
4736         for (lightindex = 0;lightindex < range;lightindex++)
4737         {
4738                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4739                 if (!light)
4740                         continue;
4741                 rtlight = &light->rtlight;
4742                 rtlight->corona_visibility = 0;
4743                 rtlight->corona_queryindex_visiblepixels = 0;
4744                 rtlight->corona_queryindex_allpixels = 0;
4745                 if (!(rtlight->flags & flag))
4746                         continue;
4747                 if (rtlight->corona <= 0)
4748                         continue;
4749                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4750                         continue;
4751                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4752         }
4753         for (i = 0;i < r_refdef.scene.numlights;i++)
4754         {
4755                 rtlight = r_refdef.scene.lights[i];
4756                 rtlight->corona_visibility = 0;
4757                 rtlight->corona_queryindex_visiblepixels = 0;
4758                 rtlight->corona_queryindex_allpixels = 0;
4759                 if (!(rtlight->flags & flag))
4760                         continue;
4761                 if (rtlight->corona <= 0)
4762                         continue;
4763                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4764         }
4765         if (usequery)
4766                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4767
4768         // now draw the coronas using the query data for intensity info
4769         for (lightindex = 0;lightindex < range;lightindex++)
4770         {
4771                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4772                 if (!light)
4773                         continue;
4774                 rtlight = &light->rtlight;
4775                 if (rtlight->corona_visibility <= 0)
4776                         continue;
4777                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4778         }
4779         for (i = 0;i < r_refdef.scene.numlights;i++)
4780         {
4781                 rtlight = r_refdef.scene.lights[i];
4782                 if (rtlight->corona_visibility <= 0)
4783                         continue;
4784                 if (gl_flashblend.integer)
4785                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4786                 else
4787                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4788         }
4789 }
4790
4791
4792
4793 dlight_t *R_Shadow_NewWorldLight(void)
4794 {
4795         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4796 }
4797
4798 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)
4799 {
4800         matrix4x4_t matrix;
4801         // validate parameters
4802         if (style < 0 || style >= MAX_LIGHTSTYLES)
4803         {
4804                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4805                 style = 0;
4806         }
4807         if (!cubemapname)
4808                 cubemapname = "";
4809
4810         // copy to light properties
4811         VectorCopy(origin, light->origin);
4812         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4813         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4814         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4815         /*
4816         light->color[0] = max(color[0], 0);
4817         light->color[1] = max(color[1], 0);
4818         light->color[2] = max(color[2], 0);
4819         */
4820         light->color[0] = color[0];
4821         light->color[1] = color[1];
4822         light->color[2] = color[2];
4823         light->radius = max(radius, 0);
4824         light->style = style;
4825         light->shadow = shadowenable;
4826         light->corona = corona;
4827         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4828         light->coronasizescale = coronasizescale;
4829         light->ambientscale = ambientscale;
4830         light->diffusescale = diffusescale;
4831         light->specularscale = specularscale;
4832         light->flags = flags;
4833
4834         // update renderable light data
4835         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4836         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);
4837 }
4838
4839 void R_Shadow_FreeWorldLight(dlight_t *light)
4840 {
4841         if (r_shadow_selectedlight == light)
4842                 r_shadow_selectedlight = NULL;
4843         R_RTLight_Uncompile(&light->rtlight);
4844         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4845 }
4846
4847 void R_Shadow_ClearWorldLights(void)
4848 {
4849         size_t lightindex;
4850         dlight_t *light;
4851         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4852         for (lightindex = 0;lightindex < range;lightindex++)
4853         {
4854                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4855                 if (light)
4856                         R_Shadow_FreeWorldLight(light);
4857         }
4858         r_shadow_selectedlight = NULL;
4859 }
4860
4861 void R_Shadow_SelectLight(dlight_t *light)
4862 {
4863         if (r_shadow_selectedlight)
4864                 r_shadow_selectedlight->selected = false;
4865         r_shadow_selectedlight = light;
4866         if (r_shadow_selectedlight)
4867                 r_shadow_selectedlight->selected = true;
4868 }
4869
4870 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4871 {
4872         // this is never batched (there can be only one)
4873         float vertex3f[12];
4874         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4875         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4876         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4877 }
4878
4879 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4880 {
4881         float intensity;
4882         float s;
4883         vec3_t spritecolor;
4884         skinframe_t *skinframe;
4885         float vertex3f[12];
4886
4887         // this is never batched (due to the ent parameter changing every time)
4888         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4889         const dlight_t *light = (dlight_t *)ent;
4890         s = EDLIGHTSPRSIZE;
4891
4892         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4893
4894         intensity = 0.5f;
4895         VectorScale(light->color, intensity, spritecolor);
4896         if (VectorLength(spritecolor) < 0.1732f)
4897                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4898         if (VectorLength(spritecolor) > 1.0f)
4899                 VectorNormalize(spritecolor);
4900
4901         // draw light sprite
4902         if (light->cubemapname[0] && !light->shadow)
4903                 skinframe = r_editlights_sprcubemapnoshadowlight;
4904         else if (light->cubemapname[0])
4905                 skinframe = r_editlights_sprcubemaplight;
4906         else if (!light->shadow)
4907                 skinframe = r_editlights_sprnoshadowlight;
4908         else
4909                 skinframe = r_editlights_sprlight;
4910
4911         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);
4912         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4913
4914         // draw selection sprite if light is selected
4915         if (light->selected)
4916         {
4917                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4918                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4919                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4920         }
4921 }
4922
4923 void R_Shadow_DrawLightSprites(void)
4924 {
4925         size_t lightindex;
4926         dlight_t *light;
4927         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4928         for (lightindex = 0;lightindex < range;lightindex++)
4929         {
4930                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4931                 if (light)
4932                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4933         }
4934         if (!r_editlights_lockcursor)
4935                 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4936 }
4937
4938 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4939 {
4940         unsigned int range;
4941         dlight_t *light;
4942         rtlight_t *rtlight;
4943         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4944         if (lightindex >= range)
4945                 return -1;
4946         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4947         if (!light)
4948                 return 0;
4949         rtlight = &light->rtlight;
4950         //if (!(rtlight->flags & flag))
4951         //      return 0;
4952         VectorCopy(rtlight->shadoworigin, origin);
4953         *radius = rtlight->radius;
4954         VectorCopy(rtlight->color, color);
4955         return 1;
4956 }
4957
4958 void R_Shadow_SelectLightInView(void)
4959 {
4960         float bestrating, rating, temp[3];
4961         dlight_t *best;
4962         size_t lightindex;
4963         dlight_t *light;
4964         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4965         best = NULL;
4966         bestrating = 0;
4967
4968         if (r_editlights_lockcursor)
4969                 return;
4970         for (lightindex = 0;lightindex < range;lightindex++)
4971         {
4972                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4973                 if (!light)
4974                         continue;
4975                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4976                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4977                 if (rating >= 0.95)
4978                 {
4979                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4980                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4981                         {
4982                                 bestrating = rating;
4983                                 best = light;
4984                         }
4985                 }
4986         }
4987         R_Shadow_SelectLight(best);
4988 }
4989
4990 void R_Shadow_LoadWorldLights(void)
4991 {
4992         int n, a, style, shadow, flags;
4993         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4994         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4995         if (cl.worldmodel == NULL)
4996         {
4997                 Con_Print("No map loaded.\n");
4998                 return;
4999         }
5000         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5001         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5002         if (lightsstring)
5003         {
5004                 s = lightsstring;
5005                 n = 0;
5006                 while (*s)
5007                 {
5008                         t = s;
5009                         /*
5010                         shadow = true;
5011                         for (;COM_Parse(t, true) && strcmp(
5012                         if (COM_Parse(t, true))
5013                         {
5014                                 if (com_token[0] == '!')
5015                                 {
5016                                         shadow = false;
5017                                         origin[0] = atof(com_token+1);
5018                                 }
5019                                 else
5020                                         origin[0] = atof(com_token);
5021                                 if (Com_Parse(t
5022                         }
5023                         */
5024                         t = s;
5025                         while (*s && *s != '\n' && *s != '\r')
5026                                 s++;
5027                         if (!*s)
5028                                 break;
5029                         tempchar = *s;
5030                         shadow = true;
5031                         // check for modifier flags
5032                         if (*t == '!')
5033                         {
5034                                 shadow = false;
5035                                 t++;
5036                         }
5037                         *s = 0;
5038 #if _MSC_VER >= 1400
5039 #define sscanf sscanf_s
5040 #endif
5041                         cubemapname[sizeof(cubemapname)-1] = 0;
5042 #if MAX_QPATH != 128
5043 #error update this code if MAX_QPATH changes
5044 #endif
5045                         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
5046 #if _MSC_VER >= 1400
5047 , sizeof(cubemapname)
5048 #endif
5049 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5050                         *s = tempchar;
5051                         if (a < 18)
5052                                 flags = LIGHTFLAG_REALTIMEMODE;
5053                         if (a < 17)
5054                                 specularscale = 1;
5055                         if (a < 16)
5056                                 diffusescale = 1;
5057                         if (a < 15)
5058                                 ambientscale = 0;
5059                         if (a < 14)
5060                                 coronasizescale = 0.25f;
5061                         if (a < 13)
5062                                 VectorClear(angles);
5063                         if (a < 10)
5064                                 corona = 0;
5065                         if (a < 9 || !strcmp(cubemapname, "\"\""))
5066                                 cubemapname[0] = 0;
5067                         // remove quotes on cubemapname
5068                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5069                         {
5070                                 size_t namelen;
5071                                 namelen = strlen(cubemapname) - 2;
5072                                 memmove(cubemapname, cubemapname + 1, namelen);
5073                                 cubemapname[namelen] = '\0';
5074                         }
5075                         if (a < 8)
5076                         {
5077                                 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);
5078                                 break;
5079                         }
5080                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5081                         if (*s == '\r')
5082                                 s++;
5083                         if (*s == '\n')
5084                                 s++;
5085                         n++;
5086                 }
5087                 if (*s)
5088                         Con_Printf("invalid rtlights file \"%s\"\n", name);
5089                 Mem_Free(lightsstring);
5090         }
5091 }
5092
5093 void R_Shadow_SaveWorldLights(void)
5094 {
5095         size_t lightindex;
5096         dlight_t *light;
5097         size_t bufchars, bufmaxchars;
5098         char *buf, *oldbuf;
5099         char name[MAX_QPATH];
5100         char line[MAX_INPUTLINE];
5101         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5102         // I hate lines which are 3 times my screen size :( --blub
5103         if (!range)
5104                 return;
5105         if (cl.worldmodel == NULL)
5106         {
5107                 Con_Print("No map loaded.\n");
5108                 return;
5109         }
5110         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5111         bufchars = bufmaxchars = 0;
5112         buf = NULL;
5113         for (lightindex = 0;lightindex < range;lightindex++)
5114         {
5115                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5116                 if (!light)
5117                         continue;
5118                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5119                         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);
5120                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5121                         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]);
5122                 else
5123                         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);
5124                 if (bufchars + strlen(line) > bufmaxchars)
5125                 {
5126                         bufmaxchars = bufchars + strlen(line) + 2048;
5127                         oldbuf = buf;
5128                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5129                         if (oldbuf)
5130                         {
5131                                 if (bufchars)
5132                                         memcpy(buf, oldbuf, bufchars);
5133                                 Mem_Free(oldbuf);
5134                         }
5135                 }
5136                 if (strlen(line))
5137                 {
5138                         memcpy(buf + bufchars, line, strlen(line));
5139                         bufchars += strlen(line);
5140                 }
5141         }
5142         if (bufchars)
5143                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5144         if (buf)
5145                 Mem_Free(buf);
5146 }
5147
5148 void R_Shadow_LoadLightsFile(void)
5149 {
5150         int n, a, style;
5151         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5152         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5153         if (cl.worldmodel == NULL)
5154         {
5155                 Con_Print("No map loaded.\n");
5156                 return;
5157         }
5158         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5159         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5160         if (lightsstring)
5161         {
5162                 s = lightsstring;
5163                 n = 0;
5164                 while (*s)
5165                 {
5166                         t = s;
5167                         while (*s && *s != '\n' && *s != '\r')
5168                                 s++;
5169                         if (!*s)
5170                                 break;
5171                         tempchar = *s;
5172                         *s = 0;
5173                         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);
5174                         *s = tempchar;
5175                         if (a < 14)
5176                         {
5177                                 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);
5178                                 break;
5179                         }
5180                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5181                         radius = bound(15, radius, 4096);
5182                         VectorScale(color, (2.0f / (8388608.0f)), color);
5183                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5184                         if (*s == '\r')
5185                                 s++;
5186                         if (*s == '\n')
5187                                 s++;
5188                         n++;
5189                 }
5190                 if (*s)
5191                         Con_Printf("invalid lights file \"%s\"\n", name);
5192                 Mem_Free(lightsstring);
5193         }
5194 }
5195
5196 // tyrlite/hmap2 light types in the delay field
5197 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5198
5199 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5200 {
5201         int entnum;
5202         int style;
5203         int islight;
5204         int skin;
5205         int pflags;
5206         //int effects;
5207         int type;
5208         int n;
5209         char *entfiledata;
5210         const char *data;
5211         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5212         char key[256], value[MAX_INPUTLINE];
5213
5214         if (cl.worldmodel == NULL)
5215         {
5216                 Con_Print("No map loaded.\n");
5217                 return;
5218         }
5219         // try to load a .ent file first
5220         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5221         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5222         // and if that is not found, fall back to the bsp file entity string
5223         if (!data)
5224                 data = cl.worldmodel->brush.entities;
5225         if (!data)
5226                 return;
5227         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5228         {
5229                 type = LIGHTTYPE_MINUSX;
5230                 origin[0] = origin[1] = origin[2] = 0;
5231                 originhack[0] = originhack[1] = originhack[2] = 0;
5232                 angles[0] = angles[1] = angles[2] = 0;
5233                 color[0] = color[1] = color[2] = 1;
5234                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5235                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5236                 fadescale = 1;
5237                 lightscale = 1;
5238                 style = 0;
5239                 skin = 0;
5240                 pflags = 0;
5241                 //effects = 0;
5242                 islight = false;
5243                 while (1)
5244                 {
5245                         if (!COM_ParseToken_Simple(&data, false, false))
5246                                 break; // error
5247                         if (com_token[0] == '}')
5248                                 break; // end of entity
5249                         if (com_token[0] == '_')
5250                                 strlcpy(key, com_token + 1, sizeof(key));
5251                         else
5252                                 strlcpy(key, com_token, sizeof(key));
5253                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5254                                 key[strlen(key)-1] = 0;
5255                         if (!COM_ParseToken_Simple(&data, false, false))
5256                                 break; // error
5257                         strlcpy(value, com_token, sizeof(value));
5258
5259                         // now that we have the key pair worked out...
5260                         if (!strcmp("light", key))
5261                         {
5262                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5263                                 if (n == 1)
5264                                 {
5265                                         // quake
5266                                         light[0] = vec[0] * (1.0f / 256.0f);
5267                                         light[1] = vec[0] * (1.0f / 256.0f);
5268                                         light[2] = vec[0] * (1.0f / 256.0f);
5269                                         light[3] = vec[0];
5270                                 }
5271                                 else if (n == 4)
5272                                 {
5273                                         // halflife
5274                                         light[0] = vec[0] * (1.0f / 255.0f);
5275                                         light[1] = vec[1] * (1.0f / 255.0f);
5276                                         light[2] = vec[2] * (1.0f / 255.0f);
5277                                         light[3] = vec[3];
5278                                 }
5279                         }
5280                         else if (!strcmp("delay", key))
5281                                 type = atoi(value);
5282                         else if (!strcmp("origin", key))
5283                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5284                         else if (!strcmp("angle", key))
5285                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5286                         else if (!strcmp("angles", key))
5287                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5288                         else if (!strcmp("color", key))
5289                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5290                         else if (!strcmp("wait", key))
5291                                 fadescale = atof(value);
5292                         else if (!strcmp("classname", key))
5293                         {
5294                                 if (!strncmp(value, "light", 5))
5295                                 {
5296                                         islight = true;
5297                                         if (!strcmp(value, "light_fluoro"))
5298                                         {
5299                                                 originhack[0] = 0;
5300                                                 originhack[1] = 0;
5301                                                 originhack[2] = 0;
5302                                                 overridecolor[0] = 1;
5303                                                 overridecolor[1] = 1;
5304                                                 overridecolor[2] = 1;
5305                                         }
5306                                         if (!strcmp(value, "light_fluorospark"))
5307                                         {
5308                                                 originhack[0] = 0;
5309                                                 originhack[1] = 0;
5310                                                 originhack[2] = 0;
5311                                                 overridecolor[0] = 1;
5312                                                 overridecolor[1] = 1;
5313                                                 overridecolor[2] = 1;
5314                                         }
5315                                         if (!strcmp(value, "light_globe"))
5316                                         {
5317                                                 originhack[0] = 0;
5318                                                 originhack[1] = 0;
5319                                                 originhack[2] = 0;
5320                                                 overridecolor[0] = 1;
5321                                                 overridecolor[1] = 0.8;
5322                                                 overridecolor[2] = 0.4;
5323                                         }
5324                                         if (!strcmp(value, "light_flame_large_yellow"))
5325                                         {
5326                                                 originhack[0] = 0;
5327                                                 originhack[1] = 0;
5328                                                 originhack[2] = 0;
5329                                                 overridecolor[0] = 1;
5330                                                 overridecolor[1] = 0.5;
5331                                                 overridecolor[2] = 0.1;
5332                                         }
5333                                         if (!strcmp(value, "light_flame_small_yellow"))
5334                                         {
5335                                                 originhack[0] = 0;
5336                                                 originhack[1] = 0;
5337                                                 originhack[2] = 0;
5338                                                 overridecolor[0] = 1;
5339                                                 overridecolor[1] = 0.5;
5340                                                 overridecolor[2] = 0.1;
5341                                         }
5342                                         if (!strcmp(value, "light_torch_small_white"))
5343                                         {
5344                                                 originhack[0] = 0;
5345                                                 originhack[1] = 0;
5346                                                 originhack[2] = 0;
5347                                                 overridecolor[0] = 1;
5348                                                 overridecolor[1] = 0.5;
5349                                                 overridecolor[2] = 0.1;
5350                                         }
5351                                         if (!strcmp(value, "light_torch_small_walltorch"))
5352                                         {
5353                                                 originhack[0] = 0;
5354                                                 originhack[1] = 0;
5355                                                 originhack[2] = 0;
5356                                                 overridecolor[0] = 1;
5357                                                 overridecolor[1] = 0.5;
5358                                                 overridecolor[2] = 0.1;
5359                                         }
5360                                 }
5361                         }
5362                         else if (!strcmp("style", key))
5363                                 style = atoi(value);
5364                         else if (!strcmp("skin", key))
5365                                 skin = (int)atof(value);
5366                         else if (!strcmp("pflags", key))
5367                                 pflags = (int)atof(value);
5368                         //else if (!strcmp("effects", key))
5369                         //      effects = (int)atof(value);
5370                         else if (cl.worldmodel->type == mod_brushq3)
5371                         {
5372                                 if (!strcmp("scale", key))
5373                                         lightscale = atof(value);
5374                                 if (!strcmp("fade", key))
5375                                         fadescale = atof(value);
5376                         }
5377                 }
5378                 if (!islight)
5379                         continue;
5380                 if (lightscale <= 0)
5381                         lightscale = 1;
5382                 if (fadescale <= 0)
5383                         fadescale = 1;
5384                 if (color[0] == color[1] && color[0] == color[2])
5385                 {
5386                         color[0] *= overridecolor[0];
5387                         color[1] *= overridecolor[1];
5388                         color[2] *= overridecolor[2];
5389                 }
5390                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5391                 color[0] = color[0] * light[0];
5392                 color[1] = color[1] * light[1];
5393                 color[2] = color[2] * light[2];
5394                 switch (type)
5395                 {
5396                 case LIGHTTYPE_MINUSX:
5397                         break;
5398                 case LIGHTTYPE_RECIPX:
5399                         radius *= 2;
5400                         VectorScale(color, (1.0f / 16.0f), color);
5401                         break;
5402                 case LIGHTTYPE_RECIPXX:
5403                         radius *= 2;
5404                         VectorScale(color, (1.0f / 16.0f), color);
5405                         break;
5406                 default:
5407                 case LIGHTTYPE_NONE:
5408                         break;
5409                 case LIGHTTYPE_SUN:
5410                         break;
5411                 case LIGHTTYPE_MINUSXX:
5412                         break;
5413                 }
5414                 VectorAdd(origin, originhack, origin);
5415                 if (radius >= 1)
5416                         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);
5417         }
5418         if (entfiledata)
5419                 Mem_Free(entfiledata);
5420 }
5421
5422
5423 void R_Shadow_SetCursorLocationForView(void)
5424 {
5425         vec_t dist, push;
5426         vec3_t dest, endpos;
5427         trace_t trace;
5428         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5429         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5430         if (trace.fraction < 1)
5431         {
5432                 dist = trace.fraction * r_editlights_cursordistance.value;
5433                 push = r_editlights_cursorpushback.value;
5434                 if (push > dist)
5435                         push = dist;
5436                 push = -push;
5437                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5438                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5439         }
5440         else
5441         {
5442                 VectorClear( endpos );
5443         }
5444         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5445         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5446         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5447 }
5448
5449 void R_Shadow_UpdateWorldLightSelection(void)
5450 {
5451         if (r_editlights.integer)
5452         {
5453                 R_Shadow_SetCursorLocationForView();
5454                 R_Shadow_SelectLightInView();
5455         }
5456         else
5457                 R_Shadow_SelectLight(NULL);
5458 }
5459
5460 void R_Shadow_EditLights_Clear_f(void)
5461 {
5462         R_Shadow_ClearWorldLights();
5463 }
5464
5465 void R_Shadow_EditLights_Reload_f(void)
5466 {
5467         if (!cl.worldmodel)
5468                 return;
5469         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5470         R_Shadow_ClearWorldLights();
5471         R_Shadow_LoadWorldLights();
5472         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5473         {
5474                 R_Shadow_LoadLightsFile();
5475                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5476                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5477         }
5478 }
5479
5480 void R_Shadow_EditLights_Save_f(void)
5481 {
5482         if (!cl.worldmodel)
5483                 return;
5484         R_Shadow_SaveWorldLights();
5485 }
5486
5487 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5488 {
5489         R_Shadow_ClearWorldLights();
5490         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5491 }
5492
5493 void R_Shadow_EditLights_ImportLightsFile_f(void)
5494 {
5495         R_Shadow_ClearWorldLights();
5496         R_Shadow_LoadLightsFile();
5497 }
5498
5499 void R_Shadow_EditLights_Spawn_f(void)
5500 {
5501         vec3_t color;
5502         if (!r_editlights.integer)
5503         {
5504                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5505                 return;
5506         }
5507         if (Cmd_Argc() != 1)
5508         {
5509                 Con_Print("r_editlights_spawn does not take parameters\n");
5510                 return;
5511         }
5512         color[0] = color[1] = color[2] = 1;
5513         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5514 }
5515
5516 void R_Shadow_EditLights_Edit_f(void)
5517 {
5518         vec3_t origin, angles, color;
5519         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5520         int style, shadows, flags, normalmode, realtimemode;
5521         char cubemapname[MAX_INPUTLINE];
5522         if (!r_editlights.integer)
5523         {
5524                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5525                 return;
5526         }
5527         if (!r_shadow_selectedlight)
5528         {
5529                 Con_Print("No selected light.\n");
5530                 return;
5531         }
5532         VectorCopy(r_shadow_selectedlight->origin, origin);
5533         VectorCopy(r_shadow_selectedlight->angles, angles);
5534         VectorCopy(r_shadow_selectedlight->color, color);
5535         radius = r_shadow_selectedlight->radius;
5536         style = r_shadow_selectedlight->style;
5537         if (r_shadow_selectedlight->cubemapname)
5538                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5539         else
5540                 cubemapname[0] = 0;
5541         shadows = r_shadow_selectedlight->shadow;
5542         corona = r_shadow_selectedlight->corona;
5543         coronasizescale = r_shadow_selectedlight->coronasizescale;
5544         ambientscale = r_shadow_selectedlight->ambientscale;
5545         diffusescale = r_shadow_selectedlight->diffusescale;
5546         specularscale = r_shadow_selectedlight->specularscale;
5547         flags = r_shadow_selectedlight->flags;
5548         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5549         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5550         if (!strcmp(Cmd_Argv(1), "origin"))
5551         {
5552                 if (Cmd_Argc() != 5)
5553                 {
5554                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5555                         return;
5556                 }
5557                 origin[0] = atof(Cmd_Argv(2));
5558                 origin[1] = atof(Cmd_Argv(3));
5559                 origin[2] = atof(Cmd_Argv(4));
5560         }
5561         else if (!strcmp(Cmd_Argv(1), "originx"))
5562         {
5563                 if (Cmd_Argc() != 3)
5564                 {
5565                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5566                         return;
5567                 }
5568                 origin[0] = atof(Cmd_Argv(2));
5569         }
5570         else if (!strcmp(Cmd_Argv(1), "originy"))
5571         {
5572                 if (Cmd_Argc() != 3)
5573                 {
5574                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5575                         return;
5576                 }
5577                 origin[1] = atof(Cmd_Argv(2));
5578         }
5579         else if (!strcmp(Cmd_Argv(1), "originz"))
5580         {
5581                 if (Cmd_Argc() != 3)
5582                 {
5583                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5584                         return;
5585                 }
5586                 origin[2] = atof(Cmd_Argv(2));
5587         }
5588         else if (!strcmp(Cmd_Argv(1), "move"))
5589         {
5590                 if (Cmd_Argc() != 5)
5591                 {
5592                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5593                         return;
5594                 }
5595                 origin[0] += atof(Cmd_Argv(2));
5596                 origin[1] += atof(Cmd_Argv(3));
5597                 origin[2] += atof(Cmd_Argv(4));
5598         }
5599         else if (!strcmp(Cmd_Argv(1), "movex"))
5600         {
5601                 if (Cmd_Argc() != 3)
5602                 {
5603                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5604                         return;
5605                 }
5606                 origin[0] += atof(Cmd_Argv(2));
5607         }
5608         else if (!strcmp(Cmd_Argv(1), "movey"))
5609         {
5610                 if (Cmd_Argc() != 3)
5611                 {
5612                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5613                         return;
5614                 }
5615                 origin[1] += atof(Cmd_Argv(2));
5616         }
5617         else if (!strcmp(Cmd_Argv(1), "movez"))
5618         {
5619                 if (Cmd_Argc() != 3)
5620                 {
5621                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5622                         return;
5623                 }
5624                 origin[2] += atof(Cmd_Argv(2));
5625         }
5626         else if (!strcmp(Cmd_Argv(1), "angles"))
5627         {
5628                 if (Cmd_Argc() != 5)
5629                 {
5630                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5631                         return;
5632                 }
5633                 angles[0] = atof(Cmd_Argv(2));
5634                 angles[1] = atof(Cmd_Argv(3));
5635                 angles[2] = atof(Cmd_Argv(4));
5636         }
5637         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5638         {
5639                 if (Cmd_Argc() != 3)
5640                 {
5641                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5642                         return;
5643                 }
5644                 angles[0] = atof(Cmd_Argv(2));
5645         }
5646         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5647         {
5648                 if (Cmd_Argc() != 3)
5649                 {
5650                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5651                         return;
5652                 }
5653                 angles[1] = atof(Cmd_Argv(2));
5654         }
5655         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5656         {
5657                 if (Cmd_Argc() != 3)
5658                 {
5659                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5660                         return;
5661                 }
5662                 angles[2] = atof(Cmd_Argv(2));
5663         }
5664         else if (!strcmp(Cmd_Argv(1), "color"))
5665         {
5666                 if (Cmd_Argc() != 5)
5667                 {
5668                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5669                         return;
5670                 }
5671                 color[0] = atof(Cmd_Argv(2));
5672                 color[1] = atof(Cmd_Argv(3));
5673                 color[2] = atof(Cmd_Argv(4));
5674         }
5675         else if (!strcmp(Cmd_Argv(1), "radius"))
5676         {
5677                 if (Cmd_Argc() != 3)
5678                 {
5679                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5680                         return;
5681                 }
5682                 radius = atof(Cmd_Argv(2));
5683         }
5684         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5685         {
5686                 if (Cmd_Argc() == 3)
5687                 {
5688                         double scale = atof(Cmd_Argv(2));
5689                         color[0] *= scale;
5690                         color[1] *= scale;
5691                         color[2] *= scale;
5692                 }
5693                 else
5694                 {
5695                         if (Cmd_Argc() != 5)
5696                         {
5697                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5698                                 return;
5699                         }
5700                         color[0] *= atof(Cmd_Argv(2));
5701                         color[1] *= atof(Cmd_Argv(3));
5702                         color[2] *= atof(Cmd_Argv(4));
5703                 }
5704         }
5705         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5706         {
5707                 if (Cmd_Argc() != 3)
5708                 {
5709                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5710                         return;
5711                 }
5712                 radius *= atof(Cmd_Argv(2));
5713         }
5714         else if (!strcmp(Cmd_Argv(1), "style"))
5715         {
5716                 if (Cmd_Argc() != 3)
5717                 {
5718                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5719                         return;
5720                 }
5721                 style = atoi(Cmd_Argv(2));
5722         }
5723         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5724         {
5725                 if (Cmd_Argc() > 3)
5726                 {
5727                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5728                         return;
5729                 }
5730                 if (Cmd_Argc() == 3)
5731                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5732                 else
5733                         cubemapname[0] = 0;
5734         }
5735         else if (!strcmp(Cmd_Argv(1), "shadows"))
5736         {
5737                 if (Cmd_Argc() != 3)
5738                 {
5739                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5740                         return;
5741                 }
5742                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5743         }
5744         else if (!strcmp(Cmd_Argv(1), "corona"))
5745         {
5746                 if (Cmd_Argc() != 3)
5747                 {
5748                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5749                         return;
5750                 }
5751                 corona = atof(Cmd_Argv(2));
5752         }
5753         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5754         {
5755                 if (Cmd_Argc() != 3)
5756                 {
5757                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5758                         return;
5759                 }
5760                 coronasizescale = atof(Cmd_Argv(2));
5761         }
5762         else if (!strcmp(Cmd_Argv(1), "ambient"))
5763         {
5764                 if (Cmd_Argc() != 3)
5765                 {
5766                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5767                         return;
5768                 }
5769                 ambientscale = atof(Cmd_Argv(2));
5770         }
5771         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5772         {
5773                 if (Cmd_Argc() != 3)
5774                 {
5775                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5776                         return;
5777                 }
5778                 diffusescale = atof(Cmd_Argv(2));
5779         }
5780         else if (!strcmp(Cmd_Argv(1), "specular"))
5781         {
5782                 if (Cmd_Argc() != 3)
5783                 {
5784                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5785                         return;
5786                 }
5787                 specularscale = atof(Cmd_Argv(2));
5788         }
5789         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5790         {
5791                 if (Cmd_Argc() != 3)
5792                 {
5793                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5794                         return;
5795                 }
5796                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5797         }
5798         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5799         {
5800                 if (Cmd_Argc() != 3)
5801                 {
5802                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5803                         return;
5804                 }
5805                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5806         }
5807         else
5808         {
5809                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5810                 Con_Print("Selected light's properties:\n");
5811                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5812                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5813                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5814                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5815                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5816                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5817                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5818                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5819                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5820                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5821                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5822                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5823                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5824                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5825                 return;
5826         }
5827         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5828         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5829 }
5830
5831 void R_Shadow_EditLights_EditAll_f(void)
5832 {
5833         size_t lightindex;
5834         dlight_t *light, *oldselected;
5835         size_t range;
5836
5837         if (!r_editlights.integer)
5838         {
5839                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5840                 return;
5841         }
5842
5843         oldselected = r_shadow_selectedlight;
5844         // EditLights doesn't seem to have a "remove" command or something so:
5845         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5846         for (lightindex = 0;lightindex < range;lightindex++)
5847         {
5848                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5849                 if (!light)
5850                         continue;
5851                 R_Shadow_SelectLight(light);
5852                 R_Shadow_EditLights_Edit_f();
5853         }
5854         // return to old selected (to not mess editing once selection is locked)
5855         R_Shadow_SelectLight(oldselected);
5856 }
5857
5858 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5859 {
5860         int lightnumber, lightcount;
5861         size_t lightindex, range;
5862         dlight_t *light;
5863         float x, y;
5864         char temp[256];
5865         if (!r_editlights.integer)
5866                 return;
5867         x = vid_conwidth.value - 240;
5868         y = 5;
5869         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5870         lightnumber = -1;
5871         lightcount = 0;
5872         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5873         for (lightindex = 0;lightindex < range;lightindex++)
5874         {
5875                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5876                 if (!light)
5877                         continue;
5878                 if (light == r_shadow_selectedlight)
5879                         lightnumber = lightindex;
5880                 lightcount++;
5881         }
5882         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;
5883         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;
5884         y += 8;
5885         if (r_shadow_selectedlight == NULL)
5886                 return;
5887         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;
5888         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;
5889         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;
5890         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;
5891         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;
5892         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;
5893         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;
5894         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;
5895         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;
5896         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;
5897         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;
5898         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;
5899         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;
5900         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;
5901         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;
5902 }
5903
5904 void R_Shadow_EditLights_ToggleShadow_f(void)
5905 {
5906         if (!r_editlights.integer)
5907         {
5908                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5909                 return;
5910         }
5911         if (!r_shadow_selectedlight)
5912         {
5913                 Con_Print("No selected light.\n");
5914                 return;
5915         }
5916         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);
5917 }
5918
5919 void R_Shadow_EditLights_ToggleCorona_f(void)
5920 {
5921         if (!r_editlights.integer)
5922         {
5923                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5924                 return;
5925         }
5926         if (!r_shadow_selectedlight)
5927         {
5928                 Con_Print("No selected light.\n");
5929                 return;
5930         }
5931         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);
5932 }
5933
5934 void R_Shadow_EditLights_Remove_f(void)
5935 {
5936         if (!r_editlights.integer)
5937         {
5938                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5939                 return;
5940         }
5941         if (!r_shadow_selectedlight)
5942         {
5943                 Con_Print("No selected light.\n");
5944                 return;
5945         }
5946         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5947         r_shadow_selectedlight = NULL;
5948 }
5949
5950 void R_Shadow_EditLights_Help_f(void)
5951 {
5952         Con_Print(
5953 "Documentation on r_editlights system:\n"
5954 "Settings:\n"
5955 "r_editlights : enable/disable editing mode\n"
5956 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5957 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5958 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5959 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5960 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5961 "Commands:\n"
5962 "r_editlights_help : this help\n"
5963 "r_editlights_clear : remove all lights\n"
5964 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5965 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5966 "r_editlights_save : save to .rtlights file\n"
5967 "r_editlights_spawn : create a light with default settings\n"
5968 "r_editlights_edit command : edit selected light - more documentation below\n"
5969 "r_editlights_remove : remove selected light\n"
5970 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5971 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5972 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5973 "Edit commands:\n"
5974 "origin x y z : set light location\n"
5975 "originx x: set x component of light location\n"
5976 "originy y: set y component of light location\n"
5977 "originz z: set z component of light location\n"
5978 "move x y z : adjust light location\n"
5979 "movex x: adjust x component of light location\n"
5980 "movey y: adjust y component of light location\n"
5981 "movez z: adjust z component of light location\n"
5982 "angles x y z : set light angles\n"
5983 "anglesx x: set x component of light angles\n"
5984 "anglesy y: set y component of light angles\n"
5985 "anglesz z: set z component of light angles\n"
5986 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5987 "radius radius : set radius (size) of light\n"
5988 "colorscale grey : multiply color of light (1 does nothing)\n"
5989 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5990 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5991 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5992 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5993 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5994 "shadows 1/0 : turn on/off shadows\n"
5995 "corona n : set corona intensity\n"
5996 "coronasize n : set corona size (0-1)\n"
5997 "ambient n : set ambient intensity (0-1)\n"
5998 "diffuse n : set diffuse intensity (0-1)\n"
5999 "specular n : set specular intensity (0-1)\n"
6000 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6001 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6002 "<nothing> : print light properties to console\n"
6003         );
6004 }
6005
6006 void R_Shadow_EditLights_CopyInfo_f(void)
6007 {
6008         if (!r_editlights.integer)
6009         {
6010                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
6011                 return;
6012         }
6013         if (!r_shadow_selectedlight)
6014         {
6015                 Con_Print("No selected light.\n");
6016                 return;
6017         }
6018         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6019         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6020         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6021         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6022         if (r_shadow_selectedlight->cubemapname)
6023                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6024         else
6025                 r_shadow_bufferlight.cubemapname[0] = 0;
6026         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6027         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6028         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6029         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6030         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6031         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6032         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6033 }
6034
6035 void R_Shadow_EditLights_PasteInfo_f(void)
6036 {
6037         if (!r_editlights.integer)
6038         {
6039                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
6040                 return;
6041         }
6042         if (!r_shadow_selectedlight)
6043         {
6044                 Con_Print("No selected light.\n");
6045                 return;
6046         }
6047         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);
6048 }
6049
6050 void R_Shadow_EditLights_Lock_f(void)
6051 {
6052         if (!r_editlights.integer)
6053         {
6054                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
6055                 return;
6056         }
6057         if (r_editlights_lockcursor)
6058         {
6059                 r_editlights_lockcursor = false;
6060                 return;
6061         }
6062         if (!r_shadow_selectedlight)
6063         {
6064                 Con_Print("No selected light to lock on.\n");
6065                 return;
6066         }
6067         r_editlights_lockcursor = true;
6068 }
6069
6070 void R_Shadow_EditLights_Init(void)
6071 {
6072         Cvar_RegisterVariable(&r_editlights);
6073         Cvar_RegisterVariable(&r_editlights_cursordistance);
6074         Cvar_RegisterVariable(&r_editlights_cursorpushback);
6075         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6076         Cvar_RegisterVariable(&r_editlights_cursorgrid);
6077         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6078         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6079         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6080         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)");
6081         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6082         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6083         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6084         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)");
6085         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6086         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6087         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6088         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6089         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6090         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6091         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)");
6092         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6093 }
6094
6095
6096
6097 /*
6098 =============================================================================
6099
6100 LIGHT SAMPLING
6101
6102 =============================================================================
6103 */
6104
6105 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6106 {
6107         VectorClear(diffusecolor);
6108         VectorClear(diffusenormal);
6109
6110         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6111         {
6112                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6113                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6114         }
6115         else
6116                 VectorSet(ambientcolor, 1, 1, 1);
6117
6118         if (dynamic)
6119         {
6120                 int i;
6121                 float f, v[3];
6122                 rtlight_t *light;
6123                 for (i = 0;i < r_refdef.scene.numlights;i++)
6124                 {
6125                         light = r_refdef.scene.lights[i];
6126                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6127                         f = 1 - VectorLength2(v);
6128                         if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6129                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6130                 }
6131         }
6132 }