03e064440070b3b1bf7f07ba36b8a08bb018a6f3
[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_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
204
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 skinframe_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_dot3 = {CVAR_SAVE, "r_shadow_dot3", "0", "enables use of (slow) per pixel lighting on GL1.3 hardware"};
264 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
265 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)"};
266 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"};
267 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
268 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
269 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
270 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
271 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
272 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
273 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
274 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
275 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
276 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
277 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)"};
278 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
279 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
280 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
281 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
282 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)"};
283 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"};
284 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
285 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
286 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"};
287 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
288 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
289 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)"};
290 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"};
291 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
292 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)"};
293 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
294 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
295 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
296 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
297 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
298 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
299 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
300 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
301 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
302 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
303 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
304 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
305 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
306 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
307 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)"};
308 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)"};
309 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
310 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"};
311 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
312 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
313 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
314 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
315 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
316 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
317 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
318 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
319 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
320 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
321
322 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
323 #define ATTENTABLESIZE 256
324 // 1D gradient, 2D circle and 3D sphere attenuation textures
325 #define ATTEN1DSIZE 32
326 #define ATTEN2DSIZE 64
327 #define ATTEN3DSIZE 32
328
329 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
330 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
331 static float r_shadow_attentable[ATTENTABLESIZE+1];
332
333 rtlight_t *r_shadow_compilingrtlight;
334 static memexpandablearray_t r_shadow_worldlightsarray;
335 dlight_t *r_shadow_selectedlight;
336 dlight_t r_shadow_bufferlight;
337 vec3_t r_editlights_cursorlocation;
338
339 extern int con_vislines;
340
341 typedef struct cubemapinfo_s
342 {
343         char basename[64];
344         rtexture_t *texture;
345 }
346 cubemapinfo_t;
347
348 #define MAX_CUBEMAPS 256
349 static int numcubemaps;
350 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
351
352 void R_Shadow_UncompileWorldLights(void);
353 void R_Shadow_ClearWorldLights(void);
354 void R_Shadow_SaveWorldLights(void);
355 void R_Shadow_LoadWorldLights(void);
356 void R_Shadow_LoadLightsFile(void);
357 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
358 void R_Shadow_EditLights_Reload_f(void);
359 void R_Shadow_ValidateCvars(void);
360 static void R_Shadow_MakeTextures(void);
361
362 #define EDLIGHTSPRSIZE                  8
363 skinframe_t *r_editlights_sprcursor;
364 skinframe_t *r_editlights_sprlight;
365 skinframe_t *r_editlights_sprnoshadowlight;
366 skinframe_t *r_editlights_sprcubemaplight;
367 skinframe_t *r_editlights_sprcubemapnoshadowlight;
368 skinframe_t *r_editlights_sprselection;
369 extern cvar_t gl_max_size;
370
371 void R_Shadow_SetShadowMode(void)
372 {
373         r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, gl_max_size.integer / 4);
374         r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
375         r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
376         r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
377         r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
378         r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
379         r_shadow_shadowmaplod = -1;
380         r_shadow_shadowmapsize = 0;
381         r_shadow_shadowmapsampler = false;
382         r_shadow_shadowmappcf = 0;
383         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
384         if(r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object)
385         {
386                 if(r_shadow_shadowmapfilterquality < 0)
387                 {
388                         if(strstr(gl_vendor, "NVIDIA")) 
389                         {
390                                 r_shadow_shadowmapsampler = gl_support_arb_shadow;
391                                 r_shadow_shadowmappcf = 1;
392                         }
393                         else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) 
394                                 r_shadow_shadowmappcf = 1;
395                         else if(strstr(gl_vendor, "ATI")) 
396                                 r_shadow_shadowmappcf = 1;
397                         else 
398                                 r_shadow_shadowmapsampler = gl_support_arb_shadow;
399                 }
400                 else 
401                 {
402                         switch (r_shadow_shadowmapfilterquality)
403                         {
404                         case 1:
405                                 r_shadow_shadowmapsampler = gl_support_arb_shadow;
406                                 break;
407                         case 2:
408                                 r_shadow_shadowmapsampler = gl_support_arb_shadow;
409                                 r_shadow_shadowmappcf = 1;
410                                 break;
411                         case 3:
412                                 r_shadow_shadowmappcf = 1;
413                                 break;
414                         case 4:
415                                 r_shadow_shadowmappcf = 2;
416                                 break;
417                         }
418                 }
419         switch (r_shadow_shadowmaptexturetype)
420         {
421         case 0:
422             r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
423             break;
424         case 1:
425             r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
426             break;
427         case 2:
428             r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
429             break;
430         default:
431                         if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
432                                 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
433                         else if(gl_texturerectangle) 
434                                 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
435                         else
436                                 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
437             break;
438                 }
439         }
440 }
441
442 void R_Shadow_FreeShadowMaps(void)
443 {
444         int i;
445
446         R_Shadow_SetShadowMode();
447
448         if (r_shadow_fborectangle)
449                 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
450         r_shadow_fborectangle = 0;
451         CHECKGLERROR
452
453         if (r_shadow_fbo2d)
454                 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
455         r_shadow_fbo2d = 0;
456         CHECKGLERROR
457         for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
458                 if (r_shadow_fbocubeside[i])
459                         qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);
460         memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
461         CHECKGLERROR
462
463         if (r_shadow_shadowmaprectangletexture)
464                 R_FreeTexture(r_shadow_shadowmaprectangletexture);
465         r_shadow_shadowmaprectangletexture = NULL;
466
467         if (r_shadow_shadowmap2dtexture)
468                 R_FreeTexture(r_shadow_shadowmap2dtexture);
469         r_shadow_shadowmap2dtexture = NULL;
470
471         for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
472                 if (r_shadow_shadowmapcubetexture[i])
473                         R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
474         memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
475
476         if (r_shadow_shadowmapvsdcttexture)
477                 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
478         r_shadow_shadowmapvsdcttexture = NULL;
479
480         CHECKGLERROR
481 }
482
483 void r_shadow_start(void)
484 {
485         // allocate vertex processing arrays
486         numcubemaps = 0;
487         r_shadow_attenuationgradienttexture = NULL;
488         r_shadow_attenuation2dtexture = NULL;
489         r_shadow_attenuation3dtexture = NULL;
490         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
491         r_shadow_shadowmaprectangletexture = NULL;
492         r_shadow_shadowmap2dtexture = NULL;
493         memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
494         r_shadow_shadowmapvsdcttexture = NULL;
495         r_shadow_shadowmapmaxsize = 0;
496         r_shadow_shadowmapsize = 0;
497         r_shadow_shadowmaplod = 0;
498         r_shadow_shadowmapfilterquality = -1;
499         r_shadow_shadowmaptexturetype = -1;
500         r_shadow_shadowmapdepthbits = 0;
501         r_shadow_shadowmapvsdct = false;
502         r_shadow_shadowmapsampler = false;
503         r_shadow_shadowmappcf = 0;
504         r_shadow_fborectangle = 0;
505         r_shadow_fbo2d = 0;
506         memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
507
508         R_Shadow_FreeShadowMaps();
509
510         r_shadow_texturepool = NULL;
511         r_shadow_filters_texturepool = NULL;
512         R_Shadow_ValidateCvars();
513         R_Shadow_MakeTextures();
514         maxshadowtriangles = 0;
515         shadowelements = NULL;
516         maxshadowvertices = 0;
517         shadowvertex3f = NULL;
518         maxvertexupdate = 0;
519         vertexupdate = NULL;
520         vertexremap = NULL;
521         vertexupdatenum = 0;
522         maxshadowmark = 0;
523         numshadowmark = 0;
524         shadowmark = NULL;
525         shadowmarklist = NULL;
526         shadowmarkcount = 0;
527         maxshadowsides = 0;
528         numshadowsides = 0;
529         shadowsides = NULL;
530         shadowsideslist = NULL;
531         r_shadow_buffer_numleafpvsbytes = 0;
532         r_shadow_buffer_visitingleafpvs = NULL;
533         r_shadow_buffer_leafpvs = NULL;
534         r_shadow_buffer_leaflist = NULL;
535         r_shadow_buffer_numsurfacepvsbytes = 0;
536         r_shadow_buffer_surfacepvs = NULL;
537         r_shadow_buffer_surfacelist = NULL;
538         r_shadow_buffer_surfacesides = NULL;
539         r_shadow_buffer_numshadowtrispvsbytes = 0;
540         r_shadow_buffer_shadowtrispvs = NULL;
541         r_shadow_buffer_numlighttrispvsbytes = 0;
542         r_shadow_buffer_lighttrispvs = NULL;
543 }
544
545 void r_shadow_shutdown(void)
546 {
547         CHECKGLERROR
548         R_Shadow_UncompileWorldLights();
549
550         R_Shadow_FreeShadowMaps();
551
552         CHECKGLERROR
553         numcubemaps = 0;
554         r_shadow_attenuationgradienttexture = NULL;
555         r_shadow_attenuation2dtexture = NULL;
556         r_shadow_attenuation3dtexture = NULL;
557         R_FreeTexturePool(&r_shadow_texturepool);
558         R_FreeTexturePool(&r_shadow_filters_texturepool);
559         maxshadowtriangles = 0;
560         if (shadowelements)
561                 Mem_Free(shadowelements);
562         shadowelements = NULL;
563         if (shadowvertex3f)
564                 Mem_Free(shadowvertex3f);
565         shadowvertex3f = NULL;
566         maxvertexupdate = 0;
567         if (vertexupdate)
568                 Mem_Free(vertexupdate);
569         vertexupdate = NULL;
570         if (vertexremap)
571                 Mem_Free(vertexremap);
572         vertexremap = NULL;
573         vertexupdatenum = 0;
574         maxshadowmark = 0;
575         numshadowmark = 0;
576         if (shadowmark)
577                 Mem_Free(shadowmark);
578         shadowmark = NULL;
579         if (shadowmarklist)
580                 Mem_Free(shadowmarklist);
581         shadowmarklist = NULL;
582         shadowmarkcount = 0;
583         maxshadowsides = 0;
584         numshadowsides = 0;
585         if (shadowsides)
586                 Mem_Free(shadowsides);
587         shadowsides = NULL;
588         if (shadowsideslist)
589                 Mem_Free(shadowsideslist);
590         shadowsideslist = NULL;
591         r_shadow_buffer_numleafpvsbytes = 0;
592         if (r_shadow_buffer_visitingleafpvs)
593                 Mem_Free(r_shadow_buffer_visitingleafpvs);
594         r_shadow_buffer_visitingleafpvs = NULL;
595         if (r_shadow_buffer_leafpvs)
596                 Mem_Free(r_shadow_buffer_leafpvs);
597         r_shadow_buffer_leafpvs = NULL;
598         if (r_shadow_buffer_leaflist)
599                 Mem_Free(r_shadow_buffer_leaflist);
600         r_shadow_buffer_leaflist = NULL;
601         r_shadow_buffer_numsurfacepvsbytes = 0;
602         if (r_shadow_buffer_surfacepvs)
603                 Mem_Free(r_shadow_buffer_surfacepvs);
604         r_shadow_buffer_surfacepvs = NULL;
605         if (r_shadow_buffer_surfacelist)
606                 Mem_Free(r_shadow_buffer_surfacelist);
607         r_shadow_buffer_surfacelist = NULL;
608         if (r_shadow_buffer_surfacesides)
609                 Mem_Free(r_shadow_buffer_surfacesides);
610         r_shadow_buffer_surfacesides = NULL;
611         r_shadow_buffer_numshadowtrispvsbytes = 0;
612         if (r_shadow_buffer_shadowtrispvs)
613                 Mem_Free(r_shadow_buffer_shadowtrispvs);
614         r_shadow_buffer_numlighttrispvsbytes = 0;
615         if (r_shadow_buffer_lighttrispvs)
616                 Mem_Free(r_shadow_buffer_lighttrispvs);
617 }
618
619 void r_shadow_newmap(void)
620 {
621         if (r_shadow_lightcorona)                 R_SkinFrame_MarkUsed(r_shadow_lightcorona);
622         if (r_editlights_sprcursor)               R_SkinFrame_MarkUsed(r_editlights_sprcursor);
623         if (r_editlights_sprlight)                R_SkinFrame_MarkUsed(r_editlights_sprlight);
624         if (r_editlights_sprnoshadowlight)        R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
625         if (r_editlights_sprcubemaplight)         R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
626         if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
627         if (r_editlights_sprselection)            R_SkinFrame_MarkUsed(r_editlights_sprselection);
628         if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
629                 R_Shadow_EditLights_Reload_f();
630 }
631
632 void R_Shadow_Help_f(void)
633 {
634         Con_Printf(
635 "Documentation on r_shadow system:\n"
636 "Settings:\n"
637 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
638 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
639 "r_shadow_debuglight : render only this light number (-1 = all)\n"
640 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
641 "r_shadow_gloss2intensity : brightness of forced gloss\n"
642 "r_shadow_glossintensity : brightness of textured gloss\n"
643 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
644 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
645 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
646 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
647 "r_shadow_portallight : use portal visibility for static light precomputation\n"
648 "r_shadow_projectdistance : shadow volume projection distance\n"
649 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
650 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
651 "r_shadow_realtime_world : use high quality world lighting mode\n"
652 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
653 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
654 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
655 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
656 "r_shadow_scissor : use scissor optimization\n"
657 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
658 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
659 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
660 "r_showlighting : useful for performance testing; bright = slow!\n"
661 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
662 "Commands:\n"
663 "r_shadow_help : this help\n"
664         );
665 }
666
667 void R_Shadow_Init(void)
668 {
669         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
670         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
671         Cvar_RegisterVariable(&r_shadow_dot3);
672         Cvar_RegisterVariable(&r_shadow_usenormalmap);
673         Cvar_RegisterVariable(&r_shadow_debuglight);
674         Cvar_RegisterVariable(&r_shadow_gloss);
675         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
676         Cvar_RegisterVariable(&r_shadow_glossintensity);
677         Cvar_RegisterVariable(&r_shadow_glossexponent);
678         Cvar_RegisterVariable(&r_shadow_gloss2exponent);
679         Cvar_RegisterVariable(&r_shadow_glossexact);
680         Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
681         Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
682         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
683         Cvar_RegisterVariable(&r_shadow_lightradiusscale);
684         Cvar_RegisterVariable(&r_shadow_portallight);
685         Cvar_RegisterVariable(&r_shadow_projectdistance);
686         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
687         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
688         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
689         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
690         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
691         Cvar_RegisterVariable(&r_shadow_realtime_world);
692         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
693         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
694         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
695         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
696         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
697         Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
698         Cvar_RegisterVariable(&r_shadow_scissor);
699         Cvar_RegisterVariable(&r_shadow_shadowmapping);
700         Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
701         Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
702         Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
703         Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
704         Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
705         Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
706         Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
707 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
708 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
709         Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
710         Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
711         Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
712         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
713         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
714         Cvar_RegisterVariable(&r_shadow_culltriangles);
715         Cvar_RegisterVariable(&r_shadow_polygonfactor);
716         Cvar_RegisterVariable(&r_shadow_polygonoffset);
717         Cvar_RegisterVariable(&r_shadow_texture3d);
718         Cvar_RegisterVariable(&r_coronas);
719         Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
720         Cvar_RegisterVariable(&r_coronas_occlusionquery);
721         Cvar_RegisterVariable(&gl_flashblend);
722         Cvar_RegisterVariable(&gl_ext_separatestencil);
723         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
724         if (gamemode == GAME_TENEBRAE)
725         {
726                 Cvar_SetValue("r_shadow_gloss", 2);
727                 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
728         }
729         Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
730         R_Shadow_EditLights_Init();
731         Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
732         maxshadowtriangles = 0;
733         shadowelements = NULL;
734         maxshadowvertices = 0;
735         shadowvertex3f = NULL;
736         maxvertexupdate = 0;
737         vertexupdate = NULL;
738         vertexremap = NULL;
739         vertexupdatenum = 0;
740         maxshadowmark = 0;
741         numshadowmark = 0;
742         shadowmark = NULL;
743         shadowmarklist = NULL;
744         shadowmarkcount = 0;
745         maxshadowsides = 0;
746         numshadowsides = 0;
747         shadowsides = NULL;
748         shadowsideslist = NULL;
749         r_shadow_buffer_numleafpvsbytes = 0;
750         r_shadow_buffer_visitingleafpvs = NULL;
751         r_shadow_buffer_leafpvs = NULL;
752         r_shadow_buffer_leaflist = NULL;
753         r_shadow_buffer_numsurfacepvsbytes = 0;
754         r_shadow_buffer_surfacepvs = NULL;
755         r_shadow_buffer_surfacelist = NULL;
756         r_shadow_buffer_surfacesides = NULL;
757         r_shadow_buffer_shadowtrispvs = NULL;
758         r_shadow_buffer_lighttrispvs = NULL;
759         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
760 }
761
762 matrix4x4_t matrix_attenuationxyz =
763 {
764         {
765                 {0.5, 0.0, 0.0, 0.5},
766                 {0.0, 0.5, 0.0, 0.5},
767                 {0.0, 0.0, 0.5, 0.5},
768                 {0.0, 0.0, 0.0, 1.0}
769         }
770 };
771
772 matrix4x4_t matrix_attenuationz =
773 {
774         {
775                 {0.0, 0.0, 0.5, 0.5},
776                 {0.0, 0.0, 0.0, 0.5},
777                 {0.0, 0.0, 0.0, 0.5},
778                 {0.0, 0.0, 0.0, 1.0}
779         }
780 };
781
782 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
783 {
784         numvertices = ((numvertices + 255) & ~255) * vertscale;
785         numtriangles = ((numtriangles + 255) & ~255) * triscale;
786         // make sure shadowelements is big enough for this volume
787         if (maxshadowtriangles < numtriangles)
788         {
789                 maxshadowtriangles = numtriangles;
790                 if (shadowelements)
791                         Mem_Free(shadowelements);
792                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
793         }
794         // make sure shadowvertex3f is big enough for this volume
795         if (maxshadowvertices < numvertices)
796         {
797                 maxshadowvertices = numvertices;
798                 if (shadowvertex3f)
799                         Mem_Free(shadowvertex3f);
800                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
801         }
802 }
803
804 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
805 {
806         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
807         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
808         int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
809         int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
810         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
811         {
812                 if (r_shadow_buffer_visitingleafpvs)
813                         Mem_Free(r_shadow_buffer_visitingleafpvs);
814                 if (r_shadow_buffer_leafpvs)
815                         Mem_Free(r_shadow_buffer_leafpvs);
816                 if (r_shadow_buffer_leaflist)
817                         Mem_Free(r_shadow_buffer_leaflist);
818                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
819                 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
820                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
821                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
822         }
823         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
824         {
825                 if (r_shadow_buffer_surfacepvs)
826                         Mem_Free(r_shadow_buffer_surfacepvs);
827                 if (r_shadow_buffer_surfacelist)
828                         Mem_Free(r_shadow_buffer_surfacelist);
829                 if (r_shadow_buffer_surfacesides)
830                         Mem_Free(r_shadow_buffer_surfacesides);
831                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
832                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
833                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
834                 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
835         }
836         if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
837         {
838                 if (r_shadow_buffer_shadowtrispvs)
839                         Mem_Free(r_shadow_buffer_shadowtrispvs);
840                 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
841                 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
842         }
843         if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
844         {
845                 if (r_shadow_buffer_lighttrispvs)
846                         Mem_Free(r_shadow_buffer_lighttrispvs);
847                 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
848                 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
849         }
850 }
851
852 void R_Shadow_PrepareShadowMark(int numtris)
853 {
854         // make sure shadowmark is big enough for this volume
855         if (maxshadowmark < numtris)
856         {
857                 maxshadowmark = numtris;
858                 if (shadowmark)
859                         Mem_Free(shadowmark);
860                 if (shadowmarklist)
861                         Mem_Free(shadowmarklist);
862                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
863                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
864                 shadowmarkcount = 0;
865         }
866         shadowmarkcount++;
867         // if shadowmarkcount wrapped we clear the array and adjust accordingly
868         if (shadowmarkcount == 0)
869         {
870                 shadowmarkcount = 1;
871                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
872         }
873         numshadowmark = 0;
874 }
875
876 void R_Shadow_PrepareShadowSides(int numtris)
877 {
878     if (maxshadowsides < numtris)
879     {
880         maxshadowsides = numtris;
881         if (shadowsides)
882                         Mem_Free(shadowsides);
883                 if (shadowsideslist)
884                         Mem_Free(shadowsideslist);
885                 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
886                 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
887         }
888         numshadowsides = 0;
889 }
890
891 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)
892 {
893         int i, j;
894         int outtriangles = 0, outvertices = 0;
895         const int *element;
896         const float *vertex;
897         float ratio, direction[3], projectvector[3];
898
899         if (projectdirection)
900                 VectorScale(projectdirection, projectdistance, projectvector);
901         else
902                 VectorClear(projectvector);
903
904         // create the vertices
905         if (projectdirection)
906         {
907                 for (i = 0;i < numshadowmarktris;i++)
908                 {
909                         element = inelement3i + shadowmarktris[i] * 3;
910                         for (j = 0;j < 3;j++)
911                         {
912                                 if (vertexupdate[element[j]] != vertexupdatenum)
913                                 {
914                                         vertexupdate[element[j]] = vertexupdatenum;
915                                         vertexremap[element[j]] = outvertices;
916                                         vertex = invertex3f + element[j] * 3;
917                                         // project one copy of the vertex according to projectvector
918                                         VectorCopy(vertex, outvertex3f);
919                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
920                                         outvertex3f += 6;
921                                         outvertices += 2;
922                                 }
923                         }
924                 }
925         }
926         else
927         {
928                 for (i = 0;i < numshadowmarktris;i++)
929                 {
930                         element = inelement3i + shadowmarktris[i] * 3;
931                         for (j = 0;j < 3;j++)
932                         {
933                                 if (vertexupdate[element[j]] != vertexupdatenum)
934                                 {
935                                         vertexupdate[element[j]] = vertexupdatenum;
936                                         vertexremap[element[j]] = outvertices;
937                                         vertex = invertex3f + element[j] * 3;
938                                         // project one copy of the vertex to the sphere radius of the light
939                                         // (FIXME: would projecting it to the light box be better?)
940                                         VectorSubtract(vertex, projectorigin, direction);
941                                         ratio = projectdistance / VectorLength(direction);
942                                         VectorCopy(vertex, outvertex3f);
943                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
944                                         outvertex3f += 6;
945                                         outvertices += 2;
946                                 }
947                         }
948                 }
949         }
950
951         if (r_shadow_frontsidecasting.integer)
952         {
953                 for (i = 0;i < numshadowmarktris;i++)
954                 {
955                         int remappedelement[3];
956                         int markindex;
957                         const int *neighbortriangle;
958
959                         markindex = shadowmarktris[i] * 3;
960                         element = inelement3i + markindex;
961                         neighbortriangle = inneighbor3i + markindex;
962                         // output the front and back triangles
963                         outelement3i[0] = vertexremap[element[0]];
964                         outelement3i[1] = vertexremap[element[1]];
965                         outelement3i[2] = vertexremap[element[2]];
966                         outelement3i[3] = vertexremap[element[2]] + 1;
967                         outelement3i[4] = vertexremap[element[1]] + 1;
968                         outelement3i[5] = vertexremap[element[0]] + 1;
969
970                         outelement3i += 6;
971                         outtriangles += 2;
972                         // output the sides (facing outward from this triangle)
973                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
974                         {
975                                 remappedelement[0] = vertexremap[element[0]];
976                                 remappedelement[1] = vertexremap[element[1]];
977                                 outelement3i[0] = remappedelement[1];
978                                 outelement3i[1] = remappedelement[0];
979                                 outelement3i[2] = remappedelement[0] + 1;
980                                 outelement3i[3] = remappedelement[1];
981                                 outelement3i[4] = remappedelement[0] + 1;
982                                 outelement3i[5] = remappedelement[1] + 1;
983
984                                 outelement3i += 6;
985                                 outtriangles += 2;
986                         }
987                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
988                         {
989                                 remappedelement[1] = vertexremap[element[1]];
990                                 remappedelement[2] = vertexremap[element[2]];
991                                 outelement3i[0] = remappedelement[2];
992                                 outelement3i[1] = remappedelement[1];
993                                 outelement3i[2] = remappedelement[1] + 1;
994                                 outelement3i[3] = remappedelement[2];
995                                 outelement3i[4] = remappedelement[1] + 1;
996                                 outelement3i[5] = remappedelement[2] + 1;
997
998                                 outelement3i += 6;
999                                 outtriangles += 2;
1000                         }
1001                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1002                         {
1003                                 remappedelement[0] = vertexremap[element[0]];
1004                                 remappedelement[2] = vertexremap[element[2]];
1005                                 outelement3i[0] = remappedelement[0];
1006                                 outelement3i[1] = remappedelement[2];
1007                                 outelement3i[2] = remappedelement[2] + 1;
1008                                 outelement3i[3] = remappedelement[0];
1009                                 outelement3i[4] = remappedelement[2] + 1;
1010                                 outelement3i[5] = remappedelement[0] + 1;
1011
1012                                 outelement3i += 6;
1013                                 outtriangles += 2;
1014                         }
1015                 }
1016         }
1017         else
1018         {
1019                 for (i = 0;i < numshadowmarktris;i++)
1020                 {
1021                         int remappedelement[3];
1022                         int markindex;
1023                         const int *neighbortriangle;
1024
1025                         markindex = shadowmarktris[i] * 3;
1026                         element = inelement3i + markindex;
1027                         neighbortriangle = inneighbor3i + markindex;
1028                         // output the front and back triangles
1029                         outelement3i[0] = vertexremap[element[2]];
1030                         outelement3i[1] = vertexremap[element[1]];
1031                         outelement3i[2] = vertexremap[element[0]];
1032                         outelement3i[3] = vertexremap[element[0]] + 1;
1033                         outelement3i[4] = vertexremap[element[1]] + 1;
1034                         outelement3i[5] = vertexremap[element[2]] + 1;
1035
1036                         outelement3i += 6;
1037                         outtriangles += 2;
1038                         // output the sides (facing outward from this triangle)
1039                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1040                         {
1041                                 remappedelement[0] = vertexremap[element[0]];
1042                                 remappedelement[1] = vertexremap[element[1]];
1043                                 outelement3i[0] = remappedelement[0];
1044                                 outelement3i[1] = remappedelement[1];
1045                                 outelement3i[2] = remappedelement[1] + 1;
1046                                 outelement3i[3] = remappedelement[0];
1047                                 outelement3i[4] = remappedelement[1] + 1;
1048                                 outelement3i[5] = remappedelement[0] + 1;
1049
1050                                 outelement3i += 6;
1051                                 outtriangles += 2;
1052                         }
1053                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1054                         {
1055                                 remappedelement[1] = vertexremap[element[1]];
1056                                 remappedelement[2] = vertexremap[element[2]];
1057                                 outelement3i[0] = remappedelement[1];
1058                                 outelement3i[1] = remappedelement[2];
1059                                 outelement3i[2] = remappedelement[2] + 1;
1060                                 outelement3i[3] = remappedelement[1];
1061                                 outelement3i[4] = remappedelement[2] + 1;
1062                                 outelement3i[5] = remappedelement[1] + 1;
1063
1064                                 outelement3i += 6;
1065                                 outtriangles += 2;
1066                         }
1067                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1068                         {
1069                                 remappedelement[0] = vertexremap[element[0]];
1070                                 remappedelement[2] = vertexremap[element[2]];
1071                                 outelement3i[0] = remappedelement[2];
1072                                 outelement3i[1] = remappedelement[0];
1073                                 outelement3i[2] = remappedelement[0] + 1;
1074                                 outelement3i[3] = remappedelement[2];
1075                                 outelement3i[4] = remappedelement[0] + 1;
1076                                 outelement3i[5] = remappedelement[2] + 1;
1077
1078                                 outelement3i += 6;
1079                                 outtriangles += 2;
1080                         }
1081                 }
1082         }
1083         if (outnumvertices)
1084                 *outnumvertices = outvertices;
1085         return outtriangles;
1086 }
1087
1088 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)
1089 {
1090         int i, j, k;
1091         int outtriangles = 0, outvertices = 0;
1092         const int *element;
1093         const float *vertex;
1094         float ratio, direction[3], projectvector[3];
1095         qboolean side[4];
1096
1097         if (projectdirection)
1098                 VectorScale(projectdirection, projectdistance, projectvector);
1099         else
1100                 VectorClear(projectvector);
1101
1102         for (i = 0;i < numshadowmarktris;i++)
1103         {
1104                 int remappedelement[3];
1105                 int markindex;
1106                 const int *neighbortriangle;
1107
1108                 markindex = shadowmarktris[i] * 3;
1109                 neighbortriangle = inneighbor3i + markindex;
1110                 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1111                 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1112                 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1113                 if (side[0] + side[1] + side[2] == 0)
1114                         continue;
1115
1116                 side[3] = side[0];
1117                 element = inelement3i + markindex;
1118
1119                 // create the vertices
1120                 for (j = 0;j < 3;j++)
1121                 {
1122                         if (side[j] + side[j+1] == 0)
1123                                 continue;
1124                         k = element[j];
1125                         if (vertexupdate[k] != vertexupdatenum)
1126                         {
1127                                 vertexupdate[k] = vertexupdatenum;
1128                                 vertexremap[k] = outvertices;
1129                                 vertex = invertex3f + k * 3;
1130                                 VectorCopy(vertex, outvertex3f);
1131                                 if (projectdirection)
1132                                 {
1133                                         // project one copy of the vertex according to projectvector
1134                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
1135                                 }
1136                                 else
1137                                 {
1138                                         // project one copy of the vertex to the sphere radius of the light
1139                                         // (FIXME: would projecting it to the light box be better?)
1140                                         VectorSubtract(vertex, projectorigin, direction);
1141                                         ratio = projectdistance / VectorLength(direction);
1142                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1143                                 }
1144                                 outvertex3f += 6;
1145                                 outvertices += 2;
1146                         }
1147                 }
1148
1149                 // output the sides (facing outward from this triangle)
1150                 if (!side[0])
1151                 {
1152                         remappedelement[0] = vertexremap[element[0]];
1153                         remappedelement[1] = vertexremap[element[1]];
1154                         outelement3i[0] = remappedelement[1];
1155                         outelement3i[1] = remappedelement[0];
1156                         outelement3i[2] = remappedelement[0] + 1;
1157                         outelement3i[3] = remappedelement[1];
1158                         outelement3i[4] = remappedelement[0] + 1;
1159                         outelement3i[5] = remappedelement[1] + 1;
1160
1161                         outelement3i += 6;
1162                         outtriangles += 2;
1163                 }
1164                 if (!side[1])
1165                 {
1166                         remappedelement[1] = vertexremap[element[1]];
1167                         remappedelement[2] = vertexremap[element[2]];
1168                         outelement3i[0] = remappedelement[2];
1169                         outelement3i[1] = remappedelement[1];
1170                         outelement3i[2] = remappedelement[1] + 1;
1171                         outelement3i[3] = remappedelement[2];
1172                         outelement3i[4] = remappedelement[1] + 1;
1173                         outelement3i[5] = remappedelement[2] + 1;
1174
1175                         outelement3i += 6;
1176                         outtriangles += 2;
1177                 }
1178                 if (!side[2])
1179                 {
1180                         remappedelement[0] = vertexremap[element[0]];
1181                         remappedelement[2] = vertexremap[element[2]];
1182                         outelement3i[0] = remappedelement[0];
1183                         outelement3i[1] = remappedelement[2];
1184                         outelement3i[2] = remappedelement[2] + 1;
1185                         outelement3i[3] = remappedelement[0];
1186                         outelement3i[4] = remappedelement[2] + 1;
1187                         outelement3i[5] = remappedelement[0] + 1;
1188
1189                         outelement3i += 6;
1190                         outtriangles += 2;
1191                 }
1192         }
1193         if (outnumvertices)
1194                 *outnumvertices = outvertices;
1195         return outtriangles;
1196 }
1197
1198 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)
1199 {
1200         int t, tend;
1201         const int *e;
1202         const float *v[3];
1203         float normal[3];
1204         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1205                 return;
1206         tend = firsttriangle + numtris;
1207         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1208         {
1209                 // surface box entirely inside light box, no box cull
1210                 if (projectdirection)
1211                 {
1212                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1213                         {
1214                                 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1215                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1216                                         shadowmarklist[numshadowmark++] = t;
1217                         }
1218                 }
1219                 else
1220                 {
1221                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1222                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1223                                         shadowmarklist[numshadowmark++] = t;
1224                 }
1225         }
1226         else
1227         {
1228                 // surface box not entirely inside light box, cull each triangle
1229                 if (projectdirection)
1230                 {
1231                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1232                         {
1233                                 v[0] = invertex3f + e[0] * 3;
1234                                 v[1] = invertex3f + e[1] * 3;
1235                                 v[2] = invertex3f + e[2] * 3;
1236                                 TriangleNormal(v[0], v[1], v[2], normal);
1237                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1238                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1239                                         shadowmarklist[numshadowmark++] = t;
1240                         }
1241                 }
1242                 else
1243                 {
1244                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1245                         {
1246                                 v[0] = invertex3f + e[0] * 3;
1247                                 v[1] = invertex3f + e[1] * 3;
1248                                 v[2] = invertex3f + e[2] * 3;
1249                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1250                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1251                                         shadowmarklist[numshadowmark++] = t;
1252                         }
1253                 }
1254         }
1255 }
1256
1257 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1258 {
1259 #if 1
1260         return false;
1261 #else
1262         if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1263                 return false;
1264         // check if the shadow volume intersects the near plane
1265         //
1266         // a ray between the eye and light origin may intersect the caster,
1267         // indicating that the shadow may touch the eye location, however we must
1268         // test the near plane (a polygon), not merely the eye location, so it is
1269         // easiest to enlarge the caster bounding shape slightly for this.
1270         // TODO
1271         return true;
1272 #endif
1273 }
1274
1275 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)
1276 {
1277         int i, tris, outverts;
1278         if (projectdistance < 0.1)
1279         {
1280                 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1281                 return;
1282         }
1283         if (!numverts || !nummarktris)
1284                 return;
1285         // make sure shadowelements is big enough for this volume
1286         if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1287                 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1288
1289         if (maxvertexupdate < numverts)
1290         {
1291                 maxvertexupdate = numverts;
1292                 if (vertexupdate)
1293                         Mem_Free(vertexupdate);
1294                 if (vertexremap)
1295                         Mem_Free(vertexremap);
1296                 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1297                 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1298                 vertexupdatenum = 0;
1299         }
1300         vertexupdatenum++;
1301         if (vertexupdatenum == 0)
1302         {
1303                 vertexupdatenum = 1;
1304                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1305                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1306         }
1307
1308         for (i = 0;i < nummarktris;i++)
1309                 shadowmark[marktris[i]] = shadowmarkcount;
1310
1311         if (r_shadow_compilingrtlight)
1312         {
1313                 // if we're compiling an rtlight, capture the mesh
1314                 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1315                 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1316                 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1317                 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1318         }
1319         else
1320         {
1321                 // decide which type of shadow to generate and set stencil mode
1322                 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1323                 // generate the sides or a solid volume, depending on type
1324                 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1325                         tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1326                 else
1327                         tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1328                 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1329                 r_refdef.stats.lights_shadowtriangles += tris;
1330                 CHECKGLERROR
1331                 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1332                 GL_LockArrays(0, outverts);
1333                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1334                 {
1335                         // increment stencil if frontface is infront of depthbuffer
1336                         GL_CullFace(r_refdef.view.cullface_front);
1337                         qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1338                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1339                         // decrement stencil if backface is infront of depthbuffer
1340                         GL_CullFace(r_refdef.view.cullface_back);
1341                         qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1342                 }
1343                 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1344                 {
1345                         // decrement stencil if backface is behind depthbuffer
1346                         GL_CullFace(r_refdef.view.cullface_front);
1347                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1348                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1349                         // increment stencil if frontface is behind depthbuffer
1350                         GL_CullFace(r_refdef.view.cullface_back);
1351                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1352                 }
1353                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1354                 GL_LockArrays(0, 0);
1355                 CHECKGLERROR
1356         }
1357 }
1358
1359 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1360 {
1361     // p1, p2, p3 are in the cubemap's local coordinate system
1362     // bias = border/(size - border)
1363         int mask = 0x3F;
1364
1365     float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1366           dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1367           dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1368         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1369         mask &= (3<<4)
1370                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1371                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1372                         | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1373     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1374         mask &= (3<<4)
1375             | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1376             | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))            
1377             | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1378
1379     dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1380     dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1381     dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1382     if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1383         mask &= (3<<0)
1384             | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1385             | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))            
1386             | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1387     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1388         mask &= (3<<0)
1389             | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1390             | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1391             | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1392
1393     dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1394     dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1395     dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1396     if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1397         mask &= (3<<2)
1398             | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1399             | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1400             | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1401     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1402         mask &= (3<<2)
1403             | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1404             | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1405             | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1406
1407         return mask;
1408 }
1409
1410 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1411 {
1412         vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1413         float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1414         int mask = 0x3F;
1415
1416         VectorSubtract(maxs, mins, radius);
1417     VectorScale(radius, 0.5f, radius);
1418     VectorAdd(mins, radius, center);
1419     Matrix4x4_Transform(worldtolight, center, lightcenter);
1420         Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1421         VectorSubtract(lightcenter, lightradius, pmin);
1422         VectorAdd(lightcenter, lightradius, pmax);
1423
1424     dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1425     dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1426     if(ap1 > bias*an1 && ap2 > bias*an2)
1427         mask &= (3<<4)
1428             | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1429             | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1430     if(an1 > bias*ap1 && an2 > bias*ap2)
1431         mask &= (3<<4)
1432             | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1433             | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1434
1435     dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1436     dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1437     if(ap1 > bias*an1 && ap2 > bias*an2)
1438         mask &= (3<<0)
1439             | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1440             | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1441     if(an1 > bias*ap1 && an2 > bias*ap2)
1442         mask &= (3<<0)
1443             | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1444             | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1445
1446     dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1447     dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1448     if(ap1 > bias*an1 && ap2 > bias*an2)
1449         mask &= (3<<2)
1450             | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1451             | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1452     if(an1 > bias*ap1 && an2 > bias*ap2)
1453         mask &= (3<<2)
1454             | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1455             | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1456
1457     return mask;
1458 }
1459
1460 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1461
1462 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1463 {
1464     // p is in the cubemap's local coordinate system
1465     // bias = border/(size - border)
1466     float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1467     float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1468     float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1469     int mask = 0x3F;
1470     if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1471     if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1472     if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1473     if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1474     if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1475     if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1476     return mask;
1477 }
1478
1479 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1480 {
1481         int i;
1482         vec3_t p, n;
1483         int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1484         float scale = (size - 2*border)/size, len;
1485         float bias = border / (float)(size - border), dp, dn, ap, an;
1486         // check if cone enclosing side would cross frustum plane 
1487         scale = 2 / (scale*scale + 2);
1488         for (i = 0;i < 5;i++)
1489         {
1490                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1491                         continue;
1492                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1493                 len = scale*VectorLength2(n);
1494                 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1495                 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1496                 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1497         }
1498         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1499         {
1500         Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1501         len = scale*VectorLength(n);
1502                 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1503                 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1504                 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1505         }
1506         // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1507         // check if frustum corners/origin cross plane sides
1508         for (i = 0;i < 5;i++)
1509         {
1510                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1511                 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1512                 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1513                 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1514                 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1515                 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1516                 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1517                 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1518                 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1519                 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1520         }
1521         return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1522 }
1523
1524 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)
1525 {
1526         int t, tend;
1527         const int *e;
1528         const float *v[3];
1529         float normal[3];
1530         vec3_t p[3];
1531         float bias;
1532         int mask, surfacemask = 0;
1533         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1534                 return 0;
1535         bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1536         tend = firsttriangle + numtris;
1537         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1538         {
1539                 // surface box entirely inside light box, no box cull
1540                 if (projectdirection)
1541                 {
1542                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1543                         {
1544                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1545                                 TriangleNormal(v[0], v[1], v[2], normal);
1546                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1547                                 {
1548                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1549                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1550                                         surfacemask |= mask;
1551                                         if(totals)
1552                                         {
1553                                                 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;
1554                                                 shadowsides[numshadowsides] = mask;
1555                                                 shadowsideslist[numshadowsides++] = t;
1556                                         }
1557                                 }
1558                         }
1559                 }
1560                 else
1561                 {
1562                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1563                         {
1564                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1565                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1566                                 {
1567                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1568                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1569                                         surfacemask |= mask;
1570                                         if(totals)
1571                                         {
1572                                                 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;
1573                                                 shadowsides[numshadowsides] = mask;
1574                                                 shadowsideslist[numshadowsides++] = t;
1575                                         }
1576                                 }
1577                         }
1578                 }
1579         }
1580         else
1581         {
1582                 // surface box not entirely inside light box, cull each triangle
1583                 if (projectdirection)
1584                 {
1585                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1586                         {
1587                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1588                                 TriangleNormal(v[0], v[1], v[2], normal);
1589                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1590                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1591                                 {
1592                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1593                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1594                                         surfacemask |= mask;
1595                                         if(totals)
1596                                         {
1597                                                 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;
1598                                                 shadowsides[numshadowsides] = mask;
1599                                                 shadowsideslist[numshadowsides++] = t;
1600                                         }
1601                                 }
1602                         }
1603                 }
1604                 else
1605                 {
1606                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1607                         {
1608                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1609                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1610                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1611                                 {
1612                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1613                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1614                                         surfacemask |= mask;
1615                                         if(totals)
1616                                         {
1617                                                 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;
1618                                                 shadowsides[numshadowsides] = mask;
1619                                                 shadowsideslist[numshadowsides++] = t;
1620                                         }
1621                                 }
1622                         }
1623                 }
1624         }
1625         return surfacemask;
1626 }
1627
1628 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)
1629 {
1630         int i, j, outtriangles = 0;
1631         int *outelement3i[6];
1632         if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1633                 return;
1634         outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1635         // make sure shadowelements is big enough for this mesh
1636         if (maxshadowtriangles < outtriangles)
1637                 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1638
1639         // compute the offset and size of the separate index lists for each cubemap side
1640         outtriangles = 0;
1641         for (i = 0;i < 6;i++)
1642         {
1643                 outelement3i[i] = shadowelements + outtriangles * 3;
1644                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1645                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1646                 outtriangles += sidetotals[i];
1647         }
1648
1649         // gather up the (sparse) triangles into separate index lists for each cubemap side
1650         for (i = 0;i < numsidetris;i++)
1651         {
1652                 const int *element = elements + sidetris[i] * 3;
1653                 for (j = 0;j < 6;j++)
1654                 {
1655                         if (sides[i] & (1 << j))
1656                         {
1657                                 outelement3i[j][0] = element[0];
1658                                 outelement3i[j][1] = element[1];
1659                                 outelement3i[j][2] = element[2];
1660                                 outelement3i[j] += 3;
1661                         }
1662                 }
1663         }
1664                         
1665         Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1666 }
1667
1668 static void R_Shadow_MakeTextures_MakeCorona(void)
1669 {
1670         float dx, dy;
1671         int x, y, a;
1672         unsigned char pixels[32][32][4];
1673         for (y = 0;y < 32;y++)
1674         {
1675                 dy = (y - 15.5f) * (1.0f / 16.0f);
1676                 for (x = 0;x < 32;x++)
1677                 {
1678                         dx = (x - 15.5f) * (1.0f / 16.0f);
1679                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1680                         a = bound(0, a, 255);
1681                         pixels[y][x][0] = a;
1682                         pixels[y][x][1] = a;
1683                         pixels[y][x][2] = a;
1684                         pixels[y][x][3] = 255;
1685                 }
1686         }
1687         r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_PRECACHE | TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1688 }
1689
1690 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1691 {
1692         float dist = sqrt(x*x+y*y+z*z);
1693         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1694         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1695         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1696 }
1697
1698 static void R_Shadow_MakeTextures(void)
1699 {
1700         int x, y, z;
1701         float intensity, dist;
1702         unsigned int *data;
1703         R_Shadow_FreeShadowMaps();
1704         R_FreeTexturePool(&r_shadow_texturepool);
1705         r_shadow_texturepool = R_AllocTexturePool();
1706         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1707         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1708         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1709         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1710         for (x = 0;x <= ATTENTABLESIZE;x++)
1711         {
1712                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1713                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1714                 r_shadow_attentable[x] = bound(0, intensity, 1);
1715         }
1716         // 1D gradient texture
1717         for (x = 0;x < ATTEN1DSIZE;x++)
1718                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1719         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);
1720         // 2D circle texture
1721         for (y = 0;y < ATTEN2DSIZE;y++)
1722                 for (x = 0;x < ATTEN2DSIZE;x++)
1723                         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);
1724         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);
1725         // 3D sphere texture
1726         if (r_shadow_texture3d.integer && gl_texture3d)
1727         {
1728                 for (z = 0;z < ATTEN3DSIZE;z++)
1729                         for (y = 0;y < ATTEN3DSIZE;y++)
1730                                 for (x = 0;x < ATTEN3DSIZE;x++)
1731                                         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));
1732                 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);
1733         }
1734         else
1735                 r_shadow_attenuation3dtexture = NULL;
1736         Mem_Free(data);
1737
1738         R_Shadow_MakeTextures_MakeCorona();
1739
1740         // Editor light sprites
1741         r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1742         "................"
1743         ".3............3."
1744         "..5...2332...5.."
1745         "...7.3....3.7..."
1746         "....7......7...."
1747         "...3.7....7.3..."
1748         "..2...7..7...2.."
1749         "..3..........3.."
1750         "..3..........3.."
1751         "..2...7..7...2.."
1752         "...3.7....7.3..."
1753         "....7......7...."
1754         "...7.3....3.7..."
1755         "..5...2332...5.."
1756         ".3............3."
1757         "................"
1758         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1759         r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1760         "................"
1761         "................"
1762         "......1111......"
1763         "....11233211...."
1764         "...1234554321..."
1765         "...1356776531..."
1766         "..124677776421.."
1767         "..135777777531.."
1768         "..135777777531.."
1769         "..124677776421.."
1770         "...1356776531..."
1771         "...1234554321..."
1772         "....11233211...."
1773         "......1111......"
1774         "................"
1775         "................"
1776         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1777         r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1778         "................"
1779         "................"
1780         "......1111......"
1781         "....11233211...."
1782         "...1234554321..."
1783         "...1356226531..."
1784         "..12462..26421.."
1785         "..1352....2531.."
1786         "..1352....2531.."
1787         "..12462..26421.."
1788         "...1356226531..."
1789         "...1234554321..."
1790         "....11233211...."
1791         "......1111......"
1792         "................"
1793         "................"
1794         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1795         r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1796         "................"
1797         "................"
1798         "......2772......"
1799         "....27755772...."
1800         "..277533335772.."
1801         "..753333333357.."
1802         "..777533335777.."
1803         "..735775577537.."
1804         "..733357753337.."
1805         "..733337733337.."
1806         "..753337733357.."
1807         "..277537735772.."
1808         "....27777772...."
1809         "......2772......"
1810         "................"
1811         "................"
1812         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1813         r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1814         "................"
1815         "................"
1816         "......2772......"
1817         "....27722772...."
1818         "..2772....2772.."
1819         "..72........27.."
1820         "..7772....2777.."
1821         "..7.27722772.7.."
1822         "..7...2772...7.."
1823         "..7....77....7.."
1824         "..72...77...27.."
1825         "..2772.77.2772.."
1826         "....27777772...."
1827         "......2772......"
1828         "................"
1829         "................"
1830         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1831         r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1832         "................"
1833         ".777752..257777."
1834         ".742........247."
1835         ".72..........27."
1836         ".7............7."
1837         ".5............5."
1838         ".2............2."
1839         "................"
1840         "................"
1841         ".2............2."
1842         ".5............5."
1843         ".7............7."
1844         ".72..........27."
1845         ".742........247."
1846         ".777752..257777."
1847         "................"
1848         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1849 }
1850
1851 void R_Shadow_ValidateCvars(void)
1852 {
1853         if (r_shadow_texture3d.integer && !gl_texture3d)
1854                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1855         if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1856                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1857         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1858                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1859 }
1860
1861 void R_Shadow_RenderMode_Begin(void)
1862 {
1863 #if 0
1864         GLint drawbuffer;
1865         GLint readbuffer;
1866 #endif
1867         R_Shadow_ValidateCvars();
1868
1869         if (!r_shadow_attenuation2dtexture
1870          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1871          || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1872          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1873                 R_Shadow_MakeTextures();
1874
1875         CHECKGLERROR
1876         R_Mesh_ColorPointer(NULL, 0, 0);
1877         R_Mesh_ResetTextureState();
1878         GL_BlendFunc(GL_ONE, GL_ZERO);
1879         GL_DepthRange(0, 1);
1880         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1881         GL_DepthTest(true);
1882         GL_DepthMask(false);
1883         GL_Color(0, 0, 0, 1);
1884         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1885
1886         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1887
1888         if (gl_ext_separatestencil.integer)
1889         {
1890                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1891                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1892         }
1893         else if (gl_ext_stenciltwoside.integer)
1894         {
1895                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1896                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1897         }
1898         else
1899         {
1900                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1901                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1902         }
1903
1904         if (r_glsl.integer && gl_support_fragment_shader)
1905                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1906         else if (gl_dot3arb && gl_texturecubemap && r_shadow_dot3.integer && gl_stencil)
1907                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1908         else
1909                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1910
1911         CHECKGLERROR
1912 #if 0
1913         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1914         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1915         r_shadow_drawbuffer = drawbuffer;
1916         r_shadow_readbuffer = readbuffer;
1917 #endif
1918         r_shadow_cullface_front = r_refdef.view.cullface_front;
1919         r_shadow_cullface_back = r_refdef.view.cullface_back;
1920 }
1921
1922 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1923 {
1924         rsurface.rtlight = rtlight;
1925 }
1926
1927 void R_Shadow_RenderMode_Reset(void)
1928 {
1929         CHECKGLERROR
1930         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1931         {
1932                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1933         }
1934         if (gl_support_ext_framebuffer_object)
1935         {
1936                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1937         }
1938 #if 0
1939         qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1940         qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1941 #endif
1942         R_SetViewport(&r_refdef.view.viewport);
1943         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1944         R_Mesh_ColorPointer(NULL, 0, 0);
1945         R_Mesh_ResetTextureState();
1946         GL_DepthRange(0, 1);
1947         GL_DepthTest(true);
1948         GL_DepthMask(false);
1949         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1950         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1951         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1952         qglStencilMask(~0);CHECKGLERROR
1953         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1954         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1955         r_refdef.view.cullface_front = r_shadow_cullface_front;
1956         r_refdef.view.cullface_back = r_shadow_cullface_back;
1957         GL_CullFace(r_refdef.view.cullface_back);
1958         GL_Color(1, 1, 1, 1);
1959         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1960         GL_BlendFunc(GL_ONE, GL_ZERO);
1961         R_SetupGenericShader(false);
1962         r_shadow_usingshadowmaprect = false;
1963         r_shadow_usingshadowmapcube = false;
1964         r_shadow_usingshadowmap2d = false;
1965         CHECKGLERROR
1966 }
1967
1968 void R_Shadow_ClearStencil(void)
1969 {
1970         CHECKGLERROR
1971         GL_Clear(GL_STENCIL_BUFFER_BIT);
1972         r_refdef.stats.lights_clears++;
1973 }
1974
1975 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1976 {
1977         r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1978         if (r_shadow_rendermode == mode)
1979                 return;
1980         CHECKGLERROR
1981         R_Shadow_RenderMode_Reset();
1982         GL_ColorMask(0, 0, 0, 0);
1983         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1984         R_SetupDepthOrShadowShader();
1985         qglDepthFunc(GL_LESS);CHECKGLERROR
1986         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1987         r_shadow_rendermode = mode;
1988         switch(mode)
1989         {
1990         default:
1991                 break;
1992         case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1993                 GL_CullFace(GL_NONE);
1994                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1995                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1996                 break;
1997         case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1998                 GL_CullFace(GL_NONE);
1999                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2000                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2001                 break;
2002         case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2003                 GL_CullFace(GL_NONE);
2004                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2005                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2006                 qglStencilMask(~0);CHECKGLERROR
2007                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2008                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2009                 qglStencilMask(~0);CHECKGLERROR
2010                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2011                 break;
2012         case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2013                 GL_CullFace(GL_NONE);
2014                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2015                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2016                 qglStencilMask(~0);CHECKGLERROR
2017                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2018                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2019                 qglStencilMask(~0);CHECKGLERROR
2020                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2021                 break;
2022         }
2023 }
2024
2025 static void R_Shadow_MakeVSDCT(void)
2026 {
2027         // maps to a 2x3 texture rectangle with normalized coordinates
2028         // +-
2029         // XX
2030         // YY
2031         // ZZ
2032         // stores abs(dir.xy), offset.xy/2.5
2033         unsigned char data[4*6] =
2034         {
2035                 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2036                 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2037                 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2038                 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2039                 0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2040                 0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2041         };
2042         r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL); 
2043 }
2044
2045 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2046 {
2047         int status;
2048         int maxsize;
2049         float nearclip, farclip, bias;
2050         r_viewport_t viewport;
2051         GLuint fbo = 0;
2052         CHECKGLERROR
2053         maxsize = r_shadow_shadowmapmaxsize;
2054         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2055         farclip = 1.0f;
2056         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2057         r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2058         r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2059         r_shadow_shadowmapside = side;
2060         r_shadow_shadowmapsize = size;
2061         if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2062         {
2063                 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2064                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2065                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2066                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2067
2068                 // complex unrolled cube approach (more flexible)
2069                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2070                         R_Shadow_MakeVSDCT();
2071                 if (!r_shadow_shadowmap2dtexture)
2072                 {
2073 #if 1
2074                         int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2075                         r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2076                         qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2077                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2078                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2079             // render depth into the fbo, do not render color at all
2080                         qglDrawBuffer(GL_NONE);CHECKGLERROR
2081                         qglReadBuffer(GL_NONE);CHECKGLERROR
2082                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2083                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2084                         {
2085                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2086                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2087                         }
2088 #endif
2089                 }
2090                 CHECKGLERROR
2091                 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2092                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2093                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2094                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2095         }
2096         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2097         {
2098                 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2099                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2100                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2101                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2102
2103                 // complex unrolled cube approach (more flexible)
2104                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2105                         R_Shadow_MakeVSDCT();
2106                 if (!r_shadow_shadowmaprectangletexture)
2107                 {
2108 #if 1
2109                         r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2110                         qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2111                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2112                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2113                         // render depth into the fbo, do not render color at all
2114                         qglDrawBuffer(GL_NONE);CHECKGLERROR
2115                         qglReadBuffer(GL_NONE);CHECKGLERROR
2116                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2117                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2118                         {
2119                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2120                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2121                         }
2122 #endif
2123                 }
2124                 CHECKGLERROR
2125                 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2126                 r_shadow_shadowmap_texturescale[0] = 1.0f;
2127                 r_shadow_shadowmap_texturescale[1] = 1.0f;
2128                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2129         }
2130         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2131         {
2132                 r_shadow_shadowmap_parameters[0] = 1.0f;
2133                 r_shadow_shadowmap_parameters[1] = 1.0f;
2134                 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2135                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2136
2137                 // simple cube approach
2138                 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2139                 {
2140  #if 1
2141                         r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2142                         qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2143                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2144                         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
2145                         // render depth into the fbo, do not render color at all
2146                         qglDrawBuffer(GL_NONE);CHECKGLERROR
2147                         qglReadBuffer(GL_NONE);CHECKGLERROR
2148                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2149                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2150                         {
2151                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2152                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2153                         }
2154  #endif
2155                 }
2156                 CHECKGLERROR
2157                 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2158                 r_shadow_shadowmap_texturescale[0] = 0.0f;
2159                 r_shadow_shadowmap_texturescale[1] = 0.0f;
2160                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2161         }
2162
2163         R_Shadow_RenderMode_Reset();
2164         if (fbo)
2165         {
2166                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2167                 R_SetupDepthOrShadowShader();
2168         }
2169         else
2170         {
2171                 R_SetupShowDepthShader();
2172                 qglClearColor(1,1,1,1);CHECKGLERROR
2173         }
2174         CHECKGLERROR
2175         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2176         GL_DepthMask(true);
2177         GL_DepthTest(true);
2178         qglClearDepth(1);
2179         CHECKGLERROR
2180
2181 init_done:
2182         R_SetViewport(&viewport);
2183         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2184         if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2185         {
2186                 int flipped = (side&1)^(side>>2);
2187                 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2188                 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2189                 GL_CullFace(r_refdef.view.cullface_back);
2190         }
2191         else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2192         {
2193                 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
2194         }
2195         if (clear)
2196                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_BUFFER_BIT);
2197         CHECKGLERROR
2198 }
2199
2200 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2201 {
2202         if (transparent)
2203         {
2204                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2205                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2206                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2207                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2208         }
2209         CHECKGLERROR
2210         R_Shadow_RenderMode_Reset();
2211         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2212         if (!transparent)
2213         {
2214                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2215         }
2216         if (stenciltest)
2217         {
2218                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2219                 // only draw light where this geometry was already rendered AND the
2220                 // stencil is 128 (values other than this mean shadow)
2221                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2222         }
2223         r_shadow_rendermode = r_shadow_lightingrendermode;
2224         // do global setup needed for the chosen lighting mode
2225         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2226         {
2227                 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2228                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2229                 CHECKGLERROR
2230                 if (shadowmapping)
2231                 {
2232                         if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2233                         {
2234                                 r_shadow_usingshadowmap2d = true;
2235                                 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2236                                 CHECKGLERROR
2237                         }
2238                         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2239                         {
2240                                 r_shadow_usingshadowmaprect = true;
2241                                 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2242                                 CHECKGLERROR
2243                         }
2244                         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2245                         {
2246                                 r_shadow_usingshadowmapcube = true;
2247                                 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2248                                 CHECKGLERROR
2249                         }
2250
2251                         if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2252                         {
2253                                 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2254                                 CHECKGLERROR
2255                         }
2256                 }
2257         }
2258         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2259                 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2260         //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2261         CHECKGLERROR
2262 }
2263
2264 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2265 {
2266         CHECKGLERROR
2267         R_Shadow_RenderMode_Reset();
2268         GL_BlendFunc(GL_ONE, GL_ONE);
2269         GL_DepthRange(0, 1);
2270         GL_DepthTest(r_showshadowvolumes.integer < 2);
2271         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2272         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2273         GL_CullFace(GL_NONE);
2274         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2275 }
2276
2277 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2278 {
2279         CHECKGLERROR
2280         R_Shadow_RenderMode_Reset();
2281         GL_BlendFunc(GL_ONE, GL_ONE);
2282         GL_DepthRange(0, 1);
2283         GL_DepthTest(r_showlighting.integer < 2);
2284         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2285         if (!transparent)
2286         {
2287                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2288         }
2289         if (stenciltest)
2290         {
2291                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2292                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2293         }
2294         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2295 }
2296
2297 void R_Shadow_RenderMode_End(void)
2298 {
2299         CHECKGLERROR
2300         R_Shadow_RenderMode_Reset();
2301         R_Shadow_RenderMode_ActiveLight(NULL);
2302         GL_DepthMask(true);
2303         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2304         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2305 }
2306
2307 int bboxedges[12][2] =
2308 {
2309         // top
2310         {0, 1}, // +X
2311         {0, 2}, // +Y
2312         {1, 3}, // Y, +X
2313         {2, 3}, // X, +Y
2314         // bottom
2315         {4, 5}, // +X
2316         {4, 6}, // +Y
2317         {5, 7}, // Y, +X
2318         {6, 7}, // X, +Y
2319         // verticals
2320         {0, 4}, // +Z
2321         {1, 5}, // X, +Z
2322         {2, 6}, // Y, +Z
2323         {3, 7}, // XY, +Z
2324 };
2325
2326 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2327 {
2328         int i, ix1, iy1, ix2, iy2;
2329         float x1, y1, x2, y2;
2330         vec4_t v, v2;
2331         float vertex[20][3];
2332         int j, k;
2333         vec4_t plane4f;
2334         int numvertices;
2335         float corner[8][4];
2336         float dist[8];
2337         int sign[8];
2338         float f;
2339
2340         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2341         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2342         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2343         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2344
2345         if (!r_shadow_scissor.integer)
2346                 return false;
2347
2348         // if view is inside the light box, just say yes it's visible
2349         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2350                 return false;
2351
2352         x1 = y1 = x2 = y2 = 0;
2353
2354         // transform all corners that are infront of the nearclip plane
2355         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2356         plane4f[3] = r_refdef.view.frustum[4].dist;
2357         numvertices = 0;
2358         for (i = 0;i < 8;i++)
2359         {
2360                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2361                 dist[i] = DotProduct4(corner[i], plane4f);
2362                 sign[i] = dist[i] > 0;
2363                 if (!sign[i])
2364                 {
2365                         VectorCopy(corner[i], vertex[numvertices]);
2366                         numvertices++;
2367                 }
2368         }
2369         // if some points are behind the nearclip, add clipped edge points to make
2370         // sure that the scissor boundary is complete
2371         if (numvertices > 0 && numvertices < 8)
2372         {
2373                 // add clipped edge points
2374                 for (i = 0;i < 12;i++)
2375                 {
2376                         j = bboxedges[i][0];
2377                         k = bboxedges[i][1];
2378                         if (sign[j] != sign[k])
2379                         {
2380                                 f = dist[j] / (dist[j] - dist[k]);
2381                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2382                                 numvertices++;
2383                         }
2384                 }
2385         }
2386
2387         // if we have no points to check, the light is behind the view plane
2388         if (!numvertices)
2389                 return true;
2390
2391         // if we have some points to transform, check what screen area is covered
2392         x1 = y1 = x2 = y2 = 0;
2393         v[3] = 1.0f;
2394         //Con_Printf("%i vertices to transform...\n", numvertices);
2395         for (i = 0;i < numvertices;i++)
2396         {
2397                 VectorCopy(vertex[i], v);
2398                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2399                 //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]);
2400                 if (i)
2401                 {
2402                         if (x1 > v2[0]) x1 = v2[0];
2403                         if (x2 < v2[0]) x2 = v2[0];
2404                         if (y1 > v2[1]) y1 = v2[1];
2405                         if (y2 < v2[1]) y2 = v2[1];
2406                 }
2407                 else
2408                 {
2409                         x1 = x2 = v2[0];
2410                         y1 = y2 = v2[1];
2411                 }
2412         }
2413
2414         // now convert the scissor rectangle to integer screen coordinates
2415         ix1 = (int)(x1 - 1.0f);
2416         iy1 = vid.height - (int)(y2 - 1.0f);
2417         ix2 = (int)(x2 + 1.0f);
2418         iy2 = vid.height - (int)(y1 + 1.0f);
2419         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2420
2421         // clamp it to the screen
2422         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2423         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2424         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2425         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2426
2427         // if it is inside out, it's not visible
2428         if (ix2 <= ix1 || iy2 <= iy1)
2429                 return true;
2430
2431         // the light area is visible, set up the scissor rectangle
2432         r_shadow_lightscissor[0] = ix1;
2433         r_shadow_lightscissor[1] = iy1;
2434         r_shadow_lightscissor[2] = ix2 - ix1;
2435         r_shadow_lightscissor[3] = iy2 - iy1;
2436
2437         r_refdef.stats.lights_scissored++;
2438         return false;
2439 }
2440
2441 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2442 {
2443         const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2444         const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2445         float *color4f = rsurface.array_color4f + 4 * firstvertex;
2446         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2447         if (r_textureunits.integer >= 3)
2448         {
2449                 if (VectorLength2(diffusecolor) > 0)
2450                 {
2451                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2452                         {
2453                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2454                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2455                                 if ((dot = DotProduct(n, v)) < 0)
2456                                 {
2457                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2458                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2459                                 }
2460                                 else
2461                                         VectorCopy(ambientcolor, color4f);
2462                                 if (r_refdef.fogenabled)
2463                                 {
2464                                         float f;
2465                                         f = RSurf_FogVertex(vertex3f);
2466                                         VectorScale(color4f, f, color4f);
2467                                 }
2468                                 color4f[3] = 1;
2469                         }
2470                 }
2471                 else
2472                 {
2473                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2474                         {
2475                                 VectorCopy(ambientcolor, color4f);
2476                                 if (r_refdef.fogenabled)
2477                                 {
2478                                         float f;
2479                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2480                                         f = RSurf_FogVertex(vertex3f);
2481                                         VectorScale(color4f, f, color4f);
2482                                 }
2483                                 color4f[3] = 1;
2484                         }
2485                 }
2486         }
2487         else if (r_textureunits.integer >= 2)
2488         {
2489                 if (VectorLength2(diffusecolor) > 0)
2490                 {
2491                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2492                         {
2493                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2494                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2495                                 {
2496                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2497                                         if ((dot = DotProduct(n, v)) < 0)
2498                                         {
2499                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2500                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2501                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2502                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2503                                         }
2504                                         else
2505                                         {
2506                                                 color4f[0] = ambientcolor[0] * distintensity;
2507                                                 color4f[1] = ambientcolor[1] * distintensity;
2508                                                 color4f[2] = ambientcolor[2] * distintensity;
2509                                         }
2510                                         if (r_refdef.fogenabled)
2511                                         {
2512                                                 float f;
2513                                                 f = RSurf_FogVertex(vertex3f);
2514                                                 VectorScale(color4f, f, color4f);
2515                                         }
2516                                 }
2517                                 else
2518                                         VectorClear(color4f);
2519                                 color4f[3] = 1;
2520                         }
2521                 }
2522                 else
2523                 {
2524                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2525                         {
2526                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2527                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2528                                 {
2529                                         color4f[0] = ambientcolor[0] * distintensity;
2530                                         color4f[1] = ambientcolor[1] * distintensity;
2531                                         color4f[2] = ambientcolor[2] * distintensity;
2532                                         if (r_refdef.fogenabled)
2533                                         {
2534                                                 float f;
2535                                                 f = RSurf_FogVertex(vertex3f);
2536                                                 VectorScale(color4f, f, color4f);
2537                                         }
2538                                 }
2539                                 else
2540                                         VectorClear(color4f);
2541                                 color4f[3] = 1;
2542                         }
2543                 }
2544         }
2545         else
2546         {
2547                 if (VectorLength2(diffusecolor) > 0)
2548                 {
2549                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2550                         {
2551                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2552                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2553                                 {
2554                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2555                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2556                                         if ((dot = DotProduct(n, v)) < 0)
2557                                         {
2558                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2559                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2560                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2561                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2562                                         }
2563                                         else
2564                                         {
2565                                                 color4f[0] = ambientcolor[0] * distintensity;
2566                                                 color4f[1] = ambientcolor[1] * distintensity;
2567                                                 color4f[2] = ambientcolor[2] * distintensity;
2568                                         }
2569                                         if (r_refdef.fogenabled)
2570                                         {
2571                                                 float f;
2572                                                 f = RSurf_FogVertex(vertex3f);
2573                                                 VectorScale(color4f, f, color4f);
2574                                         }
2575                                 }
2576                                 else
2577                                         VectorClear(color4f);
2578                                 color4f[3] = 1;
2579                         }
2580                 }
2581                 else
2582                 {
2583                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2584                         {
2585                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2586                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2587                                 {
2588                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2589                                         color4f[0] = ambientcolor[0] * distintensity;
2590                                         color4f[1] = ambientcolor[1] * distintensity;
2591                                         color4f[2] = ambientcolor[2] * distintensity;
2592                                         if (r_refdef.fogenabled)
2593                                         {
2594                                                 float f;
2595                                                 f = RSurf_FogVertex(vertex3f);
2596                                                 VectorScale(color4f, f, color4f);
2597                                         }
2598                                 }
2599                                 else
2600                                         VectorClear(color4f);
2601                                 color4f[3] = 1;
2602                         }
2603                 }
2604         }
2605 }
2606
2607 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2608
2609 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2610 {
2611         int i;
2612         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2613         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2614         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2615         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2616         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2617         float lightdir[3];
2618         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2619         {
2620                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2621                 // the cubemap normalizes this for us
2622                 out3f[0] = DotProduct(svector3f, lightdir);
2623                 out3f[1] = DotProduct(tvector3f, lightdir);
2624                 out3f[2] = DotProduct(normal3f, lightdir);
2625         }
2626 }
2627
2628 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2629 {
2630         int i;
2631         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2632         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2633         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2634         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2635         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2636         float lightdir[3], eyedir[3], halfdir[3];
2637         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2638         {
2639                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2640                 VectorNormalize(lightdir);
2641                 VectorSubtract(rsurface.localvieworigin, vertex3f, eyedir);
2642                 VectorNormalize(eyedir);
2643                 VectorAdd(lightdir, eyedir, halfdir);
2644                 // the cubemap normalizes this for us
2645                 out3f[0] = DotProduct(svector3f, halfdir);
2646                 out3f[1] = DotProduct(tvector3f, halfdir);
2647                 out3f[2] = DotProduct(normal3f, halfdir);
2648         }
2649 }
2650
2651 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)
2652 {
2653         // used to display how many times a surface is lit for level design purposes
2654         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2655 }
2656
2657 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)
2658 {
2659         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2660         R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2661         if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2662                 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2663         else
2664                 R_Mesh_ColorPointer(NULL, 0, 0);
2665         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2666         R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2667         R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2668         R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2669         R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2670         if (rsurface.texture->backgroundcurrentskinframe)
2671         {
2672                 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2673                 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2674                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2675                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2676         }
2677         //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2678         R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2679         if(rsurface.texture->colormapping)
2680         {
2681                 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2682                 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2683         }
2684         R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2685         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2686         R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2687         R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2688         R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2689         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2690         {
2691                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2692         }
2693         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2694         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2695         {
2696                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2697         }
2698 }
2699
2700 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)
2701 {
2702         // shared final code for all the dot3 layers
2703         int renders;
2704         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2705         for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2706         {
2707                 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2708                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2709         }
2710 }
2711
2712 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)
2713 {
2714         rmeshstate_t m;
2715         // colorscale accounts for how much we multiply the brightness
2716         // during combine.
2717         //
2718         // mult is how many times the final pass of the lighting will be
2719         // performed to get more brightness than otherwise possible.
2720         //
2721         // Limit mult to 64 for sanity sake.
2722         GL_Color(1,1,1,1);
2723         if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2724         {
2725                 // 3 3D combine path (Geforce3, Radeon 8500)
2726                 memset(&m, 0, sizeof(m));
2727                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2728                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2729                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2730                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2731                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2732                 m.tex[1] = R_GetTexture(basetexture);
2733                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2734                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2735                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2736                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2737                 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2738                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2739                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2740                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2741                 m.texmatrix[2] = rsurface.entitytolight;
2742                 GL_BlendFunc(GL_ONE, GL_ONE);
2743         }
2744         else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2745         {
2746                 // 2 3D combine path (Geforce3, original Radeon)
2747                 memset(&m, 0, sizeof(m));
2748                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2749                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2750                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2751                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2752                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2753                 m.tex[1] = R_GetTexture(basetexture);
2754                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2755                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2756                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2757                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2758                 GL_BlendFunc(GL_ONE, GL_ONE);
2759         }
2760         else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2761         {
2762                 // 4 2D combine path (Geforce3, Radeon 8500)
2763                 memset(&m, 0, sizeof(m));
2764                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2765                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2766                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2767                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2768                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2769                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2770                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2771                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2772                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2773                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2774                 m.tex[2] = R_GetTexture(basetexture);
2775                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2776                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2777                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2778                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2779                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2780                 {
2781                         m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2782                         m.pointer_texcoord3f[3] = rsurface.vertex3f;
2783                         m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2784                         m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2785                         m.texmatrix[3] = rsurface.entitytolight;
2786                 }
2787                 GL_BlendFunc(GL_ONE, GL_ONE);
2788         }
2789         else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2790         {
2791                 // 3 2D combine path (Geforce3, original Radeon)
2792                 memset(&m, 0, sizeof(m));
2793                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2794                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2795                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2796                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2797                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2798                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2799                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2800                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2801                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2802                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2803                 m.tex[2] = R_GetTexture(basetexture);
2804                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2805                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2806                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2807                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2808                 GL_BlendFunc(GL_ONE, GL_ONE);
2809         }
2810         else
2811         {
2812                 // 2/2/2 2D combine path (any dot3 card)
2813                 memset(&m, 0, sizeof(m));
2814                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2815                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2816                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2817                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2818                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2819                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2820                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2821                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2822                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2823                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2824                 R_Mesh_TextureState(&m);
2825                 GL_ColorMask(0,0,0,1);
2826                 GL_BlendFunc(GL_ONE, GL_ZERO);
2827                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2828
2829                 // second pass
2830                 memset(&m, 0, sizeof(m));
2831                 m.tex[0] = R_GetTexture(basetexture);
2832                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2833                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2834                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2835                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2836                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2837                 {
2838                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2839                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2840                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2841                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2842                         m.texmatrix[1] = rsurface.entitytolight;
2843                 }
2844                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2845         }
2846         // this final code is shared
2847         R_Mesh_TextureState(&m);
2848         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);
2849 }
2850
2851 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)
2852 {
2853         rmeshstate_t m;
2854         // colorscale accounts for how much we multiply the brightness
2855         // during combine.
2856         //
2857         // mult is how many times the final pass of the lighting will be
2858         // performed to get more brightness than otherwise possible.
2859         //
2860         // Limit mult to 64 for sanity sake.
2861         GL_Color(1,1,1,1);
2862         // generate normalization cubemap texcoords
2863         R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2864         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2865         {
2866                 // 3/2 3D 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.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
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                 R_Mesh_TextureState(&m);
2885                 GL_ColorMask(0,0,0,1);
2886                 GL_BlendFunc(GL_ONE, GL_ZERO);
2887                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2888
2889                 // second pass
2890                 memset(&m, 0, sizeof(m));
2891                 m.tex[0] = R_GetTexture(basetexture);
2892                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2893                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2894                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2895                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2896                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2897                 {
2898                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2899                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2900                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2901                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2902                         m.texmatrix[1] = rsurface.entitytolight;
2903                 }
2904                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2905         }
2906         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2907         {
2908                 // 1/2/2 3D combine path (original Radeon)
2909                 memset(&m, 0, sizeof(m));
2910                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2911                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2912                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2913                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2914                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2915                 R_Mesh_TextureState(&m);
2916                 GL_ColorMask(0,0,0,1);
2917                 GL_BlendFunc(GL_ONE, GL_ZERO);
2918                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2919
2920                 // second pass
2921                 memset(&m, 0, sizeof(m));
2922                 m.tex[0] = R_GetTexture(normalmaptexture);
2923                 m.texcombinergb[0] = GL_REPLACE;
2924                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2925                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2926                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2927                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2928                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2929                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2930                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2931                 m.pointer_texcoord_bufferobject[1] = 0;
2932                 m.pointer_texcoord_bufferoffset[1] = 0;
2933                 R_Mesh_TextureState(&m);
2934                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2935                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2936
2937                 // second pass
2938                 memset(&m, 0, sizeof(m));
2939                 m.tex[0] = R_GetTexture(basetexture);
2940                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2941                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2942                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2943                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2944                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2945                 {
2946                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2947                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2948                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2949                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2950                         m.texmatrix[1] = rsurface.entitytolight;
2951                 }
2952                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2953         }
2954         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2955         {
2956                 // 2/2 3D combine path (original Radeon)
2957                 memset(&m, 0, sizeof(m));
2958                 m.tex[0] = R_GetTexture(normalmaptexture);
2959                 m.texcombinergb[0] = GL_REPLACE;
2960                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2961                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2962                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2963                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2964                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2965                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2966                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2967                 m.pointer_texcoord_bufferobject[1] = 0;
2968                 m.pointer_texcoord_bufferoffset[1] = 0;
2969                 R_Mesh_TextureState(&m);
2970                 GL_ColorMask(0,0,0,1);
2971                 GL_BlendFunc(GL_ONE, GL_ZERO);
2972                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2973
2974                 // second pass
2975                 memset(&m, 0, sizeof(m));
2976                 m.tex[0] = R_GetTexture(basetexture);
2977                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2978                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2979                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2980                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2981                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2982                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2983                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2984                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2985                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2986                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2987         }
2988         else if (r_textureunits.integer >= 4)
2989         {
2990                 // 4/2 2D combine path (Geforce3, Radeon 8500)
2991                 memset(&m, 0, sizeof(m));
2992                 m.tex[0] = R_GetTexture(normalmaptexture);
2993                 m.texcombinergb[0] = GL_REPLACE;
2994                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2995                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2996                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2997                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2998                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2999                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3000                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3001                 m.pointer_texcoord_bufferobject[1] = 0;
3002                 m.pointer_texcoord_bufferoffset[1] = 0;
3003                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3004                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3005                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3006                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3007                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
3008                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
3009                 m.pointer_texcoord3f[3] = rsurface.vertex3f;
3010                 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
3011                 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
3012                 m.texmatrix[3] = rsurface.entitytoattenuationz;
3013                 R_Mesh_TextureState(&m);
3014                 GL_ColorMask(0,0,0,1);
3015                 GL_BlendFunc(GL_ONE, GL_ZERO);
3016                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3017
3018                 // second pass
3019                 memset(&m, 0, sizeof(m));
3020                 m.tex[0] = R_GetTexture(basetexture);
3021                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3022                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3023                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3024                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3025                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3026                 {
3027                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3028                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
3029                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3030                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3031                         m.texmatrix[1] = rsurface.entitytolight;
3032                 }
3033                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3034         }
3035         else
3036         {
3037                 // 2/2/2 2D combine path (any dot3 card)
3038                 memset(&m, 0, sizeof(m));
3039                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3040                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3041                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3042                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3043                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3044                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3045                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3046                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3047                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3048                 m.texmatrix[1] = rsurface.entitytoattenuationz;
3049                 R_Mesh_TextureState(&m);
3050                 GL_ColorMask(0,0,0,1);
3051                 GL_BlendFunc(GL_ONE, GL_ZERO);
3052                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3053
3054                 // second pass
3055                 memset(&m, 0, sizeof(m));
3056                 m.tex[0] = R_GetTexture(normalmaptexture);
3057                 m.texcombinergb[0] = GL_REPLACE;
3058                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3059                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3060                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3061                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3062                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3063                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3064                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3065                 m.pointer_texcoord_bufferobject[1] = 0;
3066                 m.pointer_texcoord_bufferoffset[1] = 0;
3067                 R_Mesh_TextureState(&m);
3068                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3069                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3070
3071                 // second pass
3072                 memset(&m, 0, sizeof(m));
3073                 m.tex[0] = R_GetTexture(basetexture);
3074                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3075                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3076                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3077                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3078                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3079                 {
3080                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3081                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
3082                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3083                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3084                         m.texmatrix[1] = rsurface.entitytolight;
3085                 }
3086                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3087         }
3088         // this final code is shared
3089         R_Mesh_TextureState(&m);
3090         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);
3091 }
3092
3093 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)
3094 {
3095         float glossexponent;
3096         rmeshstate_t m;
3097         // FIXME: detect blendsquare!
3098         //if (!gl_support_blendsquare)
3099         //      return;
3100         GL_Color(1,1,1,1);
3101         // generate normalization cubemap texcoords
3102         R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
3103         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
3104         {
3105                 // 2/0/0/1/2 3D combine blendsquare path
3106                 memset(&m, 0, sizeof(m));
3107                 m.tex[0] = R_GetTexture(normalmaptexture);
3108                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3109                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3110                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3111                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3112                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3113                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3114                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3115                 m.pointer_texcoord_bufferobject[1] = 0;
3116                 m.pointer_texcoord_bufferoffset[1] = 0;
3117                 R_Mesh_TextureState(&m);
3118                 GL_ColorMask(0,0,0,1);
3119                 // this squares the result
3120                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3121                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3122
3123                 // second and third pass
3124                 R_Mesh_ResetTextureState();
3125                 // square alpha in framebuffer a few times to make it shiny
3126                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3127                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3128                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3129
3130                 // fourth pass
3131                 memset(&m, 0, sizeof(m));
3132                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3133                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3134                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3135                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3136                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3137                 R_Mesh_TextureState(&m);
3138                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3139                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3140
3141                 // fifth pass
3142                 memset(&m, 0, sizeof(m));
3143                 m.tex[0] = R_GetTexture(glosstexture);
3144                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3145                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3146                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3147                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3148                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3149                 {
3150                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3151                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
3152                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3153                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3154                         m.texmatrix[1] = rsurface.entitytolight;
3155                 }
3156                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3157         }
3158         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3159         {
3160                 // 2/0/0/2 3D combine blendsquare path
3161                 memset(&m, 0, sizeof(m));
3162                 m.tex[0] = R_GetTexture(normalmaptexture);
3163                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3164                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3165                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3166                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3167                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3168                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3169                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3170                 m.pointer_texcoord_bufferobject[1] = 0;
3171                 m.pointer_texcoord_bufferoffset[1] = 0;
3172                 R_Mesh_TextureState(&m);
3173                 GL_ColorMask(0,0,0,1);
3174                 // this squares the result
3175                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3176                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3177
3178                 // second and third pass
3179                 R_Mesh_ResetTextureState();
3180                 // square alpha in framebuffer a few times to make it shiny
3181                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3182                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3183                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3184
3185                 // fourth pass
3186                 memset(&m, 0, sizeof(m));
3187                 m.tex[0] = R_GetTexture(glosstexture);
3188                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3189                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3190                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3191                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3192                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3193                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3194                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3195                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3196                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3197                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3198         }
3199         else
3200         {
3201                 // 2/0/0/2/2 2D combine blendsquare path
3202                 memset(&m, 0, sizeof(m));
3203                 m.tex[0] = R_GetTexture(normalmaptexture);
3204                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3205                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3206                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3207                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3208                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3209                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3210                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3211                 m.pointer_texcoord_bufferobject[1] = 0;
3212                 m.pointer_texcoord_bufferoffset[1] = 0;
3213                 R_Mesh_TextureState(&m);
3214                 GL_ColorMask(0,0,0,1);
3215                 // this squares the result
3216                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3217                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3218
3219                 // second and third pass
3220                 R_Mesh_ResetTextureState();
3221                 // square alpha in framebuffer a few times to make it shiny
3222                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3223                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3224                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3225
3226                 // fourth pass
3227                 memset(&m, 0, sizeof(m));
3228                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3229                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3230                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3231                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3232                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3233                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3234                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3235                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3236                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3237                 m.texmatrix[1] = rsurface.entitytoattenuationz;
3238                 R_Mesh_TextureState(&m);
3239                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3240                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3241
3242                 // fifth pass
3243                 memset(&m, 0, sizeof(m));
3244                 m.tex[0] = R_GetTexture(glosstexture);
3245                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3246                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3247                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3248                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3249                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3250                 {
3251                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3252                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
3253                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3254                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3255                         m.texmatrix[1] = rsurface.entitytolight;
3256                 }
3257                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3258         }
3259         // this final code is shared
3260         R_Mesh_TextureState(&m);
3261         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);
3262 }
3263
3264 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)
3265 {
3266         // ARB path (any Geforce, any Radeon)
3267         qboolean doambient = ambientscale > 0;
3268         qboolean dodiffuse = diffusescale > 0;
3269         qboolean dospecular = specularscale > 0;
3270         if (!doambient && !dodiffuse && !dospecular)
3271                 return;
3272         R_Mesh_ColorPointer(NULL, 0, 0);
3273         if (doambient)
3274                 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3275         if (dodiffuse)
3276                 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3277         if (dopants)
3278         {
3279                 if (doambient)
3280                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3281                 if (dodiffuse)
3282                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3283         }
3284         if (doshirt)
3285         {
3286                 if (doambient)
3287                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3288                 if (dodiffuse)
3289                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3290         }
3291         if (dospecular)
3292                 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3293 }
3294
3295 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3296 {
3297         int renders;
3298         int i;
3299         int stop;
3300         int newfirstvertex;
3301         int newlastvertex;
3302         int newnumtriangles;
3303         int *newe;
3304         const int *e;
3305         float *c;
3306         int maxtriangles = 4096;
3307         int newelements[4096*3];
3308         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3309         for (renders = 0;renders < 64;renders++)
3310         {
3311                 stop = true;
3312                 newfirstvertex = 0;
3313                 newlastvertex = 0;
3314                 newnumtriangles = 0;
3315                 newe = newelements;
3316                 // due to low fillrate on the cards this vertex lighting path is
3317                 // designed for, we manually cull all triangles that do not
3318                 // contain a lit vertex
3319                 // this builds batches of triangles from multiple surfaces and
3320                 // renders them at once
3321                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3322                 {
3323                         if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3324                         {
3325                                 if (newnumtriangles)
3326                                 {
3327                                         newfirstvertex = min(newfirstvertex, e[0]);
3328                                         newlastvertex  = max(newlastvertex, e[0]);
3329                                 }
3330                                 else
3331                                 {
3332                                         newfirstvertex = e[0];
3333                                         newlastvertex = e[0];
3334                                 }
3335                                 newfirstvertex = min(newfirstvertex, e[1]);
3336                                 newlastvertex  = max(newlastvertex, e[1]);
3337                                 newfirstvertex = min(newfirstvertex, e[2]);
3338                                 newlastvertex  = max(newlastvertex, e[2]);
3339                                 newe[0] = e[0];
3340                                 newe[1] = e[1];
3341                                 newe[2] = e[2];
3342                                 newnumtriangles++;
3343                                 newe += 3;
3344                                 if (newnumtriangles >= maxtriangles)
3345                                 {
3346                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3347                                         newnumtriangles = 0;
3348                                         newe = newelements;
3349                                         stop = false;
3350                                 }
3351                         }
3352                 }
3353                 if (newnumtriangles >= 1)
3354                 {
3355                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3356                         stop = false;
3357                 }
3358                 // if we couldn't find any lit triangles, exit early
3359                 if (stop)
3360                         break;
3361                 // now reduce the intensity for the next overbright pass
3362                 // we have to clamp to 0 here incase the drivers have improper
3363                 // handling of negative colors
3364                 // (some old drivers even have improper handling of >1 color)
3365                 stop = true;
3366                 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3367                 {
3368                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3369                         {
3370                                 c[0] = max(0, c[0] - 1);
3371                                 c[1] = max(0, c[1] - 1);
3372                                 c[2] = max(0, c[2] - 1);
3373                                 stop = false;
3374                         }
3375                         else
3376                                 VectorClear(c);
3377                 }
3378                 // another check...
3379                 if (stop)
3380                         break;
3381         }
3382 }
3383
3384 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)
3385 {
3386         // OpenGL 1.1 path (anything)
3387         float ambientcolorbase[3], diffusecolorbase[3];
3388         float ambientcolorpants[3], diffusecolorpants[3];
3389         float ambientcolorshirt[3], diffusecolorshirt[3];
3390         rmeshstate_t m;
3391         VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3392         VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3393         VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3394         VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3395         VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3396         VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3397         memset(&m, 0, sizeof(m));
3398         m.tex[0] = R_GetTexture(basetexture);
3399         m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3400         m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3401         m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3402         m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3403         if (r_textureunits.integer >= 2)
3404         {
3405                 // voodoo2 or TNT
3406                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3407                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3408                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3409                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3410                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3411                 if (r_textureunits.integer >= 3)
3412                 {
3413                         // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off)
3414                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3415                         m.texmatrix[2] = rsurface.entitytoattenuationz;
3416                         m.pointer_texcoord3f[2] = rsurface.vertex3f;
3417                         m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3418                         m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3419                 }
3420         }
3421         R_Mesh_TextureState(&m);
3422         //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3423         R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3424         if (dopants)
3425         {
3426                 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3427                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3428         }
3429         if (doshirt)
3430         {
3431                 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3432                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3433         }
3434 }
3435
3436 extern cvar_t gl_lightmaps;
3437 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)
3438 {
3439         float ambientscale, diffusescale, specularscale;
3440         qboolean negated;
3441         vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3442         rtexture_t *nmap;
3443         // calculate colors to render this texture with
3444         lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3445         lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3446         lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3447         ambientscale = rsurface.rtlight->ambientscale;
3448         diffusescale = rsurface.rtlight->diffusescale;
3449         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3450         if (!r_shadow_usenormalmap.integer)
3451         {
3452                 ambientscale += 1.0f * diffusescale;
3453                 diffusescale = 0;
3454                 specularscale = 0;
3455         }
3456         if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3457                 return;
3458         negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && gl_support_ext_blend_subtract;
3459         if(negated)
3460         {
3461                 VectorNegate(lightcolorbase, lightcolorbase);
3462                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3463         }
3464         RSurf_SetupDepthAndCulling();
3465         nmap = rsurface.texture->currentskinframe->nmap;
3466         if (gl_lightmaps.integer)
3467                 nmap = r_texture_blanknormalmap;
3468         if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3469         {
3470                 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL &