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