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