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