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