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