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