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