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