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