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