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