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