changed rtlight compiled cluster list/pvs to leaf list/pvs to enable slightly more...
[xonotic/darkplaces.git] / r_shadow.c
1
2 /*
3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
9
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
15
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
20
21 Patent warning:
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
26 shadows do not lie.
27
28
29
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
36
37
38
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
44 in some ideal cases).
45
46
47
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however.  Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
57
58
59
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
65
66
67
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
76
77
78
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
82
83
84
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
89
90
91
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
96
97
98
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
105
106
107
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
112 */
113
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
117 #include "portals.h"
118 #include "image.h"
119
120 extern void R_Shadow_EditLights_Init(void);
121
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
126
127 int r_shadowstage = SHADOWSTAGE_NONE;
128
129 mempool_t *r_shadow_mempool;
130
131 int maxshadowelements;
132 int *shadowelements;
133
134 int maxshadowmark;
135 int numshadowmark;
136 int *shadowmark;
137 int *shadowmarklist;
138 int shadowmarkcount;
139
140 int maxvertexupdate;
141 int *vertexupdate;
142 int *vertexremap;
143 int vertexupdatenum;
144
145 int r_shadow_buffer_numleafpvsbytes;
146 qbyte *r_shadow_buffer_leafpvs;
147 int *r_shadow_buffer_leaflist;
148
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
152
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankwhitecubetexture;
158
159 // lights are reloaded when this changes
160 char r_shadow_mapname[MAX_QPATH];
161
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
164
165 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
166 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
167 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
168 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
169 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
170 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
171 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
172 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
173 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
174 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
175 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
176 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
177 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
178 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
179 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
180 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
181 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
182 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
183 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
184 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
185 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
186 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
187 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
188 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
189 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
192 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
193 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
194 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
195 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
196 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
197 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
198 cvar_t r_editlights = {0, "r_editlights", "0"};
199 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
200 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
201 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
202 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
203 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
204 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
205 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
206
207 float r_shadow_attenpower, r_shadow_attenscale;
208
209 rtlight_t *r_shadow_compilingrtlight;
210 dlight_t *r_shadow_worldlightchain;
211 dlight_t *r_shadow_selectedlight;
212 dlight_t r_shadow_bufferlight;
213 vec3_t r_editlights_cursorlocation;
214
215 rtexture_t *lighttextures[5];
216
217 extern int con_vislines;
218
219 typedef struct cubemapinfo_s
220 {
221         char basename[64];
222         rtexture_t *texture;
223 }
224 cubemapinfo_t;
225
226 #define MAX_CUBEMAPS 256
227 static int numcubemaps;
228 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
229
230 #define SHADERPERMUTATION_SPECULAR (1<<0)
231 #define SHADERPERMUTATION_FOG (1<<1)
232 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
233 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
234 #define SHADERPERMUTATION_COUNT (1<<4)
235
236 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
237
238 void R_Shadow_UncompileWorldLights(void);
239 void R_Shadow_ClearWorldLights(void);
240 void R_Shadow_SaveWorldLights(void);
241 void R_Shadow_LoadWorldLights(void);
242 void R_Shadow_LoadLightsFile(void);
243 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
244 void R_Shadow_EditLights_Reload_f(void);
245 void R_Shadow_ValidateCvars(void);
246 static void R_Shadow_MakeTextures(void);
247 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
248
249 const char *builtinshader_light_vert =
250 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
251 "// written by Forest 'LordHavoc' Hale\n"
252 "\n"
253 "uniform vec3 LightPosition;\n"
254 "\n"
255 "varying vec2 TexCoord;\n"
256 "varying vec3 CubeVector;\n"
257 "varying vec3 LightVector;\n"
258 "\n"
259 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
260 "uniform vec3 EyePosition;\n"
261 "varying vec3 EyeVector;\n"
262 "#endif\n"
263 "\n"
264 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
265 "\n"
266 "void main(void)\n"
267 "{\n"
268 "       // copy the surface texcoord\n"
269 "       TexCoord = gl_MultiTexCoord0.st;\n"
270 "\n"
271 "       // transform vertex position into light attenuation/cubemap space\n"
272 "       // (-1 to +1 across the light box)\n"
273 "       CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
274 "\n"
275 "       // transform unnormalized light direction into tangent space\n"
276 "       // (we use unnormalized to ensure that it interpolates correctly and then\n"
277 "       //  normalize it per pixel)\n"
278 "       vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
279 "       LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
280 "       LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
281 "       LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
282 "\n"
283 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
284 "       // transform unnormalized eye direction into tangent space\n"
285 "       vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
286 "       EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
287 "       EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
288 "       EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
289 "#endif\n"
290 "\n"
291 "       // transform vertex to camera space, using ftransform to match non-VS\n"
292 "       // rendering\n"
293 "       gl_Position = ftransform();\n"
294 "}\n"
295 ;
296
297 const char *builtinshader_light_frag =
298 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
299 "// written by Forest 'LordHavoc' Hale\n"
300 "\n"
301 "uniform vec3 LightColor;\n"
302 "\n"
303 "#ifdef USEOFFSETMAPPING\n"
304 "uniform float OffsetMapping_Scale;\n"
305 "uniform float OffsetMapping_Bias;\n"
306 "#endif\n"
307 "#ifdef USESPECULAR\n"
308 "uniform float SpecularPower;\n"
309 "#endif\n"
310 "#ifdef USEFOG\n"
311 "uniform float FogRangeRecip;\n"
312 "#endif\n"
313 "uniform float AmbientScale;\n"
314 "uniform float DiffuseScale;\n"
315 "#ifdef USESPECULAR\n"
316 "uniform float SpecularScale;\n"
317 "#endif\n"
318 "\n"
319 "uniform sampler2D Texture_Normal;\n"
320 "uniform sampler2D Texture_Color;\n"
321 "#ifdef USESPECULAR\n"
322 "uniform sampler2D Texture_Gloss;\n"
323 "#endif\n"
324 "#ifdef USECUBEFILTER\n"
325 "uniform samplerCube Texture_Cube;\n"
326 "#endif\n"
327 "#ifdef USEFOG\n"
328 "uniform sampler2D Texture_FogMask;\n"
329 "#endif\n"
330 "\n"
331 "varying vec2 TexCoord;\n"
332 "varying vec3 CubeVector;\n"
333 "varying vec3 LightVector;\n"
334 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
335 "varying vec3 EyeVector;\n"
336 "#endif\n"
337 "\n"
338 "void main(void)\n"
339 "{\n"
340 "       // attenuation\n"
341 "       //\n"
342 "       // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
343 "       // center and sharp falloff at the edge, this is about the most efficient\n"
344 "       // we can get away with as far as providing illumination.\n"
345 "       //\n"
346 "       // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
347 "       // provide significant illumination, large = slow = pain.\n"
348 "       float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
349 "\n"
350 "#ifdef USEFOG\n"
351 "       // apply fog\n"
352 "       colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
353 "#endif\n"
354 "\n"
355 "#ifdef USEOFFSETMAPPING\n"
356 "       // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
357 "       vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
358 "       vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
359 "       TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
360 "       TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
361 "#define TexCoord TexCoordOffset\n"
362 "#endif\n"
363 "\n"
364 "       // get the texels - with a blendmap we'd need to blend multiple here\n"
365 "       vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
366 "       vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
367 "#ifdef USESPECULAR\n"
368 "       vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
369 "#endif\n"
370 "\n"
371 "       // calculate shading\n"
372 "       vec3 diffusenormal = normalize(LightVector);\n"
373 "       vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
374 "#ifdef USESPECULAR\n"
375 "       color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
376 "#endif\n"
377 "\n"
378 "#ifdef USECUBEFILTER\n"
379 "       // apply light cubemap filter\n"
380 "       color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
381 "#endif\n"
382 "\n"
383 "       // calculate fragment color\n"
384 "       gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
385 "}\n"
386 ;
387
388 void r_shadow_start(void)
389 {
390         int i;
391         // allocate vertex processing arrays
392         numcubemaps = 0;
393         r_shadow_normalcubetexture = NULL;
394         r_shadow_attenuation2dtexture = NULL;
395         r_shadow_attenuation3dtexture = NULL;
396         r_shadow_blankwhitecubetexture = NULL;
397         r_shadow_texturepool = NULL;
398         r_shadow_filters_texturepool = NULL;
399         R_Shadow_ValidateCvars();
400         R_Shadow_MakeTextures();
401         maxshadowelements = 0;
402         shadowelements = NULL;
403         maxvertexupdate = 0;
404         vertexupdate = NULL;
405         vertexremap = NULL;
406         vertexupdatenum = 0;
407         maxshadowmark = 0;
408         numshadowmark = 0;
409         shadowmark = NULL;
410         shadowmarklist = NULL;
411         shadowmarkcount = 0;
412         r_shadow_buffer_numleafpvsbytes = 0;
413         r_shadow_buffer_leafpvs = NULL;
414         r_shadow_buffer_leaflist = NULL;
415         r_shadow_buffer_numsurfacepvsbytes = 0;
416         r_shadow_buffer_surfacepvs = NULL;
417         r_shadow_buffer_surfacelist = NULL;
418         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
419                 r_shadow_program_light[i] = 0;
420         if (gl_support_fragment_shader)
421         {
422                 char *vertstring, *fragstring;
423                 int vertstrings_count;
424                 int fragstrings_count;
425                 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
426                 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
427                 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
428                 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
429                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
430                 {
431                         vertstrings_count = 0;
432                         fragstrings_count = 0;
433                         if (i & SHADERPERMUTATION_SPECULAR)
434                         {
435                                 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
436                                 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
437                         }
438                         if (i & SHADERPERMUTATION_FOG)
439                         {
440                                 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
441                                 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
442                         }
443                         if (i & SHADERPERMUTATION_CUBEFILTER)
444                         {
445                                 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
446                                 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
447                         }
448                         if (i & SHADERPERMUTATION_OFFSETMAPPING)
449                         {
450                                 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
451                                 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
452                         }
453                         vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
454                         fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
455                         r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
456                         if (!r_shadow_program_light[i])
457                         {
458                                 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
459                                 continue;
460                         }
461                         qglUseProgramObjectARB(r_shadow_program_light[i]);
462                         qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
463                         qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
464                         if (i & SHADERPERMUTATION_SPECULAR)
465                         {
466                                 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
467                         }
468                         if (i & SHADERPERMUTATION_CUBEFILTER)
469                         {
470                                 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
471                         }
472                         if (i & SHADERPERMUTATION_FOG)
473                         {
474                                 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
475                         }
476                 }
477                 qglUseProgramObjectARB(0);
478                 if (fragstring)
479                         Mem_Free(fragstring);
480                 if (vertstring)
481                         Mem_Free(vertstring);
482         }
483 }
484
485 void r_shadow_shutdown(void)
486 {
487         int i;
488         R_Shadow_UncompileWorldLights();
489         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
490         {
491                 if (r_shadow_program_light[i])
492                 {
493                         GL_Backend_FreeProgram(r_shadow_program_light[i]);
494                         r_shadow_program_light[i] = 0;
495                 }
496         }
497         numcubemaps = 0;
498         r_shadow_normalcubetexture = NULL;
499         r_shadow_attenuation2dtexture = NULL;
500         r_shadow_attenuation3dtexture = NULL;
501         r_shadow_blankwhitecubetexture = NULL;
502         R_FreeTexturePool(&r_shadow_texturepool);
503         R_FreeTexturePool(&r_shadow_filters_texturepool);
504         maxshadowelements = 0;
505         if (shadowelements)
506                 Mem_Free(shadowelements);
507         shadowelements = NULL;
508         maxvertexupdate = 0;
509         if (vertexupdate)
510                 Mem_Free(vertexupdate);
511         vertexupdate = NULL;
512         if (vertexremap)
513                 Mem_Free(vertexremap);
514         vertexremap = NULL;
515         vertexupdatenum = 0;
516         maxshadowmark = 0;
517         numshadowmark = 0;
518         if (shadowmark)
519                 Mem_Free(shadowmark);
520         shadowmark = NULL;
521         if (shadowmarklist)
522                 Mem_Free(shadowmarklist);
523         shadowmarklist = NULL;
524         shadowmarkcount = 0;
525         r_shadow_buffer_numleafpvsbytes = 0;
526         if (r_shadow_buffer_leafpvs)
527                 Mem_Free(r_shadow_buffer_leafpvs);
528         r_shadow_buffer_leafpvs = NULL;
529         if (r_shadow_buffer_leaflist)
530                 Mem_Free(r_shadow_buffer_leaflist);
531         r_shadow_buffer_leaflist = NULL;
532         r_shadow_buffer_numsurfacepvsbytes = 0;
533         if (r_shadow_buffer_surfacepvs)
534                 Mem_Free(r_shadow_buffer_surfacepvs);
535         r_shadow_buffer_surfacepvs = NULL;
536         if (r_shadow_buffer_surfacelist)
537                 Mem_Free(r_shadow_buffer_surfacelist);
538         r_shadow_buffer_surfacelist = NULL;
539 }
540
541 void r_shadow_newmap(void)
542 {
543 }
544
545 void R_Shadow_Help_f(void)
546 {
547         Con_Printf(
548 "Documentation on r_shadow system:\n"
549 "Settings:\n"
550 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
551 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
552 "r_shadow_debuglight : render only this light number (-1 = all)\n"
553 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
554 "r_shadow_gloss2intensity : brightness of forced gloss\n"
555 "r_shadow_glossintensity : brightness of textured gloss\n"
556 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
557 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
558 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
559 "r_shadow_portallight : use portal visibility for static light precomputation\n"
560 "r_shadow_projectdistance : shadow volume projection distance\n"
561 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
562 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
563 "r_shadow_realtime_world : use high quality world lighting mode\n"
564 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
565 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
566 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
567 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
568 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
569 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
570 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
571 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
572 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
573 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
574 "r_shadow_scissor : use scissor optimization\n"
575 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
576 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
577 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
578 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
579 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
580 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
581 "Commands:\n"
582 "r_shadow_help : this help\n"
583         );
584 }
585
586 void R_Shadow_Init(void)
587 {
588         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
589         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
590         Cvar_RegisterVariable(&r_shadow_cull);
591         Cvar_RegisterVariable(&r_shadow_debuglight);
592         Cvar_RegisterVariable(&r_shadow_gloss);
593         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
594         Cvar_RegisterVariable(&r_shadow_glossintensity);
595         Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
596         Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
597         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
598         Cvar_RegisterVariable(&r_shadow_portallight);
599         Cvar_RegisterVariable(&r_shadow_projectdistance);
600         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
601         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
602         Cvar_RegisterVariable(&r_shadow_realtime_world);
603         Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
604         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
605         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
606         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
607         Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
608         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
609         Cvar_RegisterVariable(&r_shadow_scissor);
610         Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
611         Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
612         Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
613         Cvar_RegisterVariable(&r_shadow_texture3d);
614         Cvar_RegisterVariable(&r_shadow_visiblelighting);
615         Cvar_RegisterVariable(&r_shadow_visiblevolumes);
616         Cvar_RegisterVariable(&r_shadow_glsl);
617         Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
618         Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
619         Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
620         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
621         if (gamemode == GAME_TENEBRAE)
622         {
623                 Cvar_SetValue("r_shadow_gloss", 2);
624                 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
625         }
626         Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
627         R_Shadow_EditLights_Init();
628         r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
629         r_shadow_worldlightchain = NULL;
630         maxshadowelements = 0;
631         shadowelements = NULL;
632         maxvertexupdate = 0;
633         vertexupdate = NULL;
634         vertexremap = NULL;
635         vertexupdatenum = 0;
636         maxshadowmark = 0;
637         numshadowmark = 0;
638         shadowmark = NULL;
639         shadowmarklist = NULL;
640         shadowmarkcount = 0;
641         r_shadow_buffer_numleafpvsbytes = 0;
642         r_shadow_buffer_leafpvs = NULL;
643         r_shadow_buffer_leaflist = NULL;
644         r_shadow_buffer_numsurfacepvsbytes = 0;
645         r_shadow_buffer_surfacepvs = NULL;
646         r_shadow_buffer_surfacelist = NULL;
647         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
648 }
649
650 static matrix4x4_t matrix_attenuationxyz =
651 {
652         {
653                 {0.5, 0.0, 0.0, 0.5},
654                 {0.0, 0.5, 0.0, 0.5},
655                 {0.0, 0.0, 0.5, 0.5},
656                 {0.0, 0.0, 0.0, 1.0}
657         }
658 };
659
660 static matrix4x4_t matrix_attenuationz =
661 {
662         {
663                 {0.0, 0.0, 0.5, 0.5},
664                 {0.0, 0.0, 0.0, 0.5},
665                 {0.0, 0.0, 0.0, 0.5},
666                 {0.0, 0.0, 0.0, 1.0}
667         }
668 };
669
670 int *R_Shadow_ResizeShadowElements(int numtris)
671 {
672         // make sure shadowelements is big enough for this volume
673         if (maxshadowelements < numtris * 24)
674         {
675                 maxshadowelements = numtris * 24;
676                 if (shadowelements)
677                         Mem_Free(shadowelements);
678                 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
679         }
680         return shadowelements;
681 }
682
683 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
684 {
685         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
686         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
687         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
688         {
689                 if (r_shadow_buffer_leafpvs)
690                         Mem_Free(r_shadow_buffer_leafpvs);
691                 if (r_shadow_buffer_leaflist)
692                         Mem_Free(r_shadow_buffer_leaflist);
693                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
694                 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
695                 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
696         }
697         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
698         {
699                 if (r_shadow_buffer_surfacepvs)
700                         Mem_Free(r_shadow_buffer_surfacepvs);
701                 if (r_shadow_buffer_surfacelist)
702                         Mem_Free(r_shadow_buffer_surfacelist);
703                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
704                 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
705                 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
706         }
707 }
708
709 void R_Shadow_PrepareShadowMark(int numtris)
710 {
711         // make sure shadowmark is big enough for this volume
712         if (maxshadowmark < numtris)
713         {
714                 maxshadowmark = numtris;
715                 if (shadowmark)
716                         Mem_Free(shadowmark);
717                 if (shadowmarklist)
718                         Mem_Free(shadowmarklist);
719                 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
720                 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
721                 shadowmarkcount = 0;
722         }
723         shadowmarkcount++;
724         // if shadowmarkcount wrapped we clear the array and adjust accordingly
725         if (shadowmarkcount == 0)
726         {
727                 shadowmarkcount = 1;
728                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
729         }
730         numshadowmark = 0;
731 }
732
733 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
734 {
735         int i, j;
736         int outtriangles = 0, outvertices = 0;
737         const int *element;
738         const float *vertex;
739
740         if (maxvertexupdate < innumvertices)
741         {
742                 maxvertexupdate = innumvertices;
743                 if (vertexupdate)
744                         Mem_Free(vertexupdate);
745                 if (vertexremap)
746                         Mem_Free(vertexremap);
747                 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
748                 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
749                 vertexupdatenum = 0;
750         }
751         vertexupdatenum++;
752         if (vertexupdatenum == 0)
753         {
754                 vertexupdatenum = 1;
755                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
756                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
757         }
758
759         for (i = 0;i < numshadowmarktris;i++)
760                 shadowmark[shadowmarktris[i]] = shadowmarkcount;
761
762         for (i = 0;i < numshadowmarktris;i++)
763         {
764                 element = inelement3i + shadowmarktris[i] * 3;
765                 // make sure the vertices are created
766                 for (j = 0;j < 3;j++)
767                 {
768                         if (vertexupdate[element[j]] != vertexupdatenum)
769                         {
770                                 float ratio, direction[3];
771                                 vertexupdate[element[j]] = vertexupdatenum;
772                                 vertexremap[element[j]] = outvertices;
773                                 vertex = invertex3f + element[j] * 3;
774                                 // project one copy of the vertex to the sphere radius of the light
775                                 // (FIXME: would projecting it to the light box be better?)
776                                 VectorSubtract(vertex, projectorigin, direction);
777                                 ratio = projectdistance / VectorLength(direction);
778                                 VectorCopy(vertex, outvertex3f);
779                                 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
780                                 outvertex3f += 6;
781                                 outvertices += 2;
782                         }
783                 }
784         }
785
786         for (i = 0;i < numshadowmarktris;i++)
787         {
788                 int remappedelement[3];
789                 int markindex;
790                 const int *neighbortriangle;
791
792                 markindex = shadowmarktris[i] * 3;
793                 element = inelement3i + markindex;
794                 neighbortriangle = inneighbor3i + markindex;
795                 // output the front and back triangles
796                 outelement3i[0] = vertexremap[element[0]];
797                 outelement3i[1] = vertexremap[element[1]];
798                 outelement3i[2] = vertexremap[element[2]];
799                 outelement3i[3] = vertexremap[element[2]] + 1;
800                 outelement3i[4] = vertexremap[element[1]] + 1;
801                 outelement3i[5] = vertexremap[element[0]] + 1;
802
803                 outelement3i += 6;
804                 outtriangles += 2;
805                 // output the sides (facing outward from this triangle)
806                 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
807                 {
808                         remappedelement[0] = vertexremap[element[0]];
809                         remappedelement[1] = vertexremap[element[1]];
810                         outelement3i[0] = remappedelement[1];
811                         outelement3i[1] = remappedelement[0];
812                         outelement3i[2] = remappedelement[0] + 1;
813                         outelement3i[3] = remappedelement[1];
814                         outelement3i[4] = remappedelement[0] + 1;
815                         outelement3i[5] = remappedelement[1] + 1;
816
817                         outelement3i += 6;
818                         outtriangles += 2;
819                 }
820                 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
821                 {
822                         remappedelement[1] = vertexremap[element[1]];
823                         remappedelement[2] = vertexremap[element[2]];
824                         outelement3i[0] = remappedelement[2];
825                         outelement3i[1] = remappedelement[1];
826                         outelement3i[2] = remappedelement[1] + 1;
827                         outelement3i[3] = remappedelement[2];
828                         outelement3i[4] = remappedelement[1] + 1;
829                         outelement3i[5] = remappedelement[2] + 1;
830
831                         outelement3i += 6;
832                         outtriangles += 2;
833                 }
834                 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
835                 {
836                         remappedelement[0] = vertexremap[element[0]];
837                         remappedelement[2] = vertexremap[element[2]];
838                         outelement3i[0] = remappedelement[0];
839                         outelement3i[1] = remappedelement[2];
840                         outelement3i[2] = remappedelement[2] + 1;
841                         outelement3i[3] = remappedelement[0];
842                         outelement3i[4] = remappedelement[2] + 1;
843                         outelement3i[5] = remappedelement[0] + 1;
844
845                         outelement3i += 6;
846                         outtriangles += 2;
847                 }
848         }
849         if (outnumvertices)
850                 *outnumvertices = outvertices;
851         return outtriangles;
852 }
853
854 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
855 {
856         int tris, outverts;
857         if (projectdistance < 0.1)
858         {
859                 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
860                 return;
861         }
862         if (!numverts || !nummarktris)
863                 return;
864         // make sure shadowelements is big enough for this volume
865         if (maxshadowelements < nummarktris * 24)
866                 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
867         tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
868         R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
869 }
870
871 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
872 {
873         int t, tend;
874         const int *e;
875         const float *v[3];
876         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
877                 return;
878         tend = firsttriangle + numtris;
879         if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
880          && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
881          && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
882         {
883                 // surface box entirely inside light box, no box cull
884                 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
885                         if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
886                                 shadowmarklist[numshadowmark++] = t;
887         }
888         else
889         {
890                 // surface box not entirely inside light box, cull each triangle
891                 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
892                 {
893                         v[0] = invertex3f + e[0] * 3;
894                         v[1] = invertex3f + e[1] * 3;
895                         v[2] = invertex3f + e[2] * 3;
896                         if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
897                          && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
898                          && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
899                          && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
900                          && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
901                          && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
902                          && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
903                                 shadowmarklist[numshadowmark++] = t;
904                 }
905         }
906 }
907
908 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
909 {
910         rmeshstate_t m;
911         if (r_shadow_compilingrtlight)
912         {
913                 // if we're compiling an rtlight, capture the mesh
914                 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
915                 return;
916         }
917         memset(&m, 0, sizeof(m));
918         m.pointer_vertex = vertex3f;
919         R_Mesh_State(&m);
920         GL_LockArrays(0, numvertices);
921         if (r_shadowstage == SHADOWSTAGE_STENCIL)
922         {
923                 // increment stencil if backface is behind depthbuffer
924                 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
925                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
926                 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
927                 c_rt_shadowmeshes++;
928                 c_rt_shadowtris += numtriangles;
929                 // decrement stencil if frontface is behind depthbuffer
930                 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
931                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
932         }
933         R_Mesh_Draw(0, numvertices, numtriangles, element3i);
934         c_rt_shadowmeshes++;
935         c_rt_shadowtris += numtriangles;
936         GL_LockArrays(0, 0);
937 }
938
939 static void R_Shadow_MakeTextures(void)
940 {
941         int x, y, z, d, side;
942         float v[3], s, t, intensity;
943         qbyte *data;
944         R_FreeTexturePool(&r_shadow_texturepool);
945         r_shadow_texturepool = R_AllocTexturePool();
946         r_shadow_attenpower = r_shadow_lightattenuationpower.value;
947         r_shadow_attenscale = r_shadow_lightattenuationscale.value;
948 #define NORMSIZE 64
949 #define ATTEN2DSIZE 64
950 #define ATTEN3DSIZE 32
951         data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
952         r_shadow_blankwhitecubetexture = NULL;
953         r_shadow_normalcubetexture = NULL;
954         if (gl_texturecubemap)
955         {
956                 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
957                 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
958                 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
959                 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
960                 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
961                 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
962                 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
963                 for (side = 0;side < 6;side++)
964                 {
965                         for (y = 0;y < NORMSIZE;y++)
966                         {
967                                 for (x = 0;x < NORMSIZE;x++)
968                                 {
969                                         s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
970                                         t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
971                                         switch(side)
972                                         {
973                                         case 0:
974                                                 v[0] = 1;
975                                                 v[1] = -t;
976                                                 v[2] = -s;
977                                                 break;
978                                         case 1:
979                                                 v[0] = -1;
980                                                 v[1] = -t;
981                                                 v[2] = s;
982                                                 break;
983                                         case 2:
984                                                 v[0] = s;
985                                                 v[1] = 1;
986                                                 v[2] = t;
987                                                 break;
988                                         case 3:
989                                                 v[0] = s;
990                                                 v[1] = -1;
991                                                 v[2] = -t;
992                                                 break;
993                                         case 4:
994                                                 v[0] = s;
995                                                 v[1] = -t;
996                                                 v[2] = 1;
997                                                 break;
998                                         case 5:
999                                                 v[0] = -s;
1000                                                 v[1] = -t;
1001                                                 v[2] = -1;
1002                                                 break;
1003                                         }
1004                                         intensity = 127.0f / sqrt(DotProduct(v, v));
1005                                         data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1006                                         data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1007                                         data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1008                                         data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1009                                 }
1010                         }
1011                 }
1012                 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1013         }
1014         for (y = 0;y < ATTEN2DSIZE;y++)
1015         {
1016                 for (x = 0;x < ATTEN2DSIZE;x++)
1017                 {
1018                         v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1019                         v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1020                         v[2] = 0;
1021                         intensity = 1.0f - sqrt(DotProduct(v, v));
1022                         if (intensity > 0)
1023                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1024                         d = bound(0, intensity, 255);
1025                         data[(y*ATTEN2DSIZE+x)*4+0] = d;
1026                         data[(y*ATTEN2DSIZE+x)*4+1] = d;
1027                         data[(y*ATTEN2DSIZE+x)*4+2] = d;
1028                         data[(y*ATTEN2DSIZE+x)*4+3] = d;
1029                 }
1030         }
1031         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1032         if (r_shadow_texture3d.integer)
1033         {
1034                 for (z = 0;z < ATTEN3DSIZE;z++)
1035                 {
1036                         for (y = 0;y < ATTEN3DSIZE;y++)
1037                         {
1038                                 for (x = 0;x < ATTEN3DSIZE;x++)
1039                                 {
1040                                         v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1041                                         v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1042                                         v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1043                                         intensity = 1.0f - sqrt(DotProduct(v, v));
1044                                         if (intensity > 0)
1045                                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1046                                         d = bound(0, intensity, 255);
1047                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1048                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1049                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1050                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1051                                 }
1052                         }
1053                 }
1054                 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1055         }
1056         Mem_Free(data);
1057 }
1058
1059 void R_Shadow_ValidateCvars(void)
1060 {
1061         if (r_shadow_texture3d.integer && !gl_texture3d)
1062                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1063         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1064                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1065 }
1066
1067 void R_Shadow_Stage_Begin(void)
1068 {
1069         rmeshstate_t m;
1070
1071         R_Shadow_ValidateCvars();
1072
1073         if (!r_shadow_attenuation2dtexture
1074          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1075          || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1076          || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1077                 R_Shadow_MakeTextures();
1078
1079         memset(&m, 0, sizeof(m));
1080         GL_BlendFunc(GL_ONE, GL_ZERO);
1081         GL_DepthMask(false);
1082         GL_DepthTest(true);
1083         R_Mesh_State(&m);
1084         GL_Color(0, 0, 0, 1);
1085         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1086         qglEnable(GL_CULL_FACE);
1087         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1088         r_shadowstage = SHADOWSTAGE_NONE;
1089 }
1090
1091 void R_Shadow_Stage_ShadowVolumes(void)
1092 {
1093         rmeshstate_t m;
1094         memset(&m, 0, sizeof(m));
1095         R_Mesh_State(&m);
1096         GL_Color(1, 1, 1, 1);
1097         GL_ColorMask(0, 0, 0, 0);
1098         GL_BlendFunc(GL_ONE, GL_ZERO);
1099         GL_DepthMask(false);
1100         GL_DepthTest(true);
1101         qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1102         //if (r_shadow_shadow_polygonoffset.value != 0)
1103         //{
1104         //      qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1105         //      qglEnable(GL_POLYGON_OFFSET_FILL);
1106         //}
1107         //else
1108         //      qglDisable(GL_POLYGON_OFFSET_FILL);
1109         qglDepthFunc(GL_LESS);
1110         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1111         qglEnable(GL_STENCIL_TEST);
1112         qglStencilFunc(GL_ALWAYS, 128, ~0);
1113         if (gl_ext_stenciltwoside.integer)
1114         {
1115                 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1116                 qglDisable(GL_CULL_FACE);
1117                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1118                 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1119                 qglStencilMask(~0);
1120                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1121                 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1122                 qglStencilMask(~0);
1123                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1124         }
1125         else
1126         {
1127                 r_shadowstage = SHADOWSTAGE_STENCIL;
1128                 qglEnable(GL_CULL_FACE);
1129                 qglStencilMask(~0);
1130                 // this is changed by every shadow render so its value here is unimportant
1131                 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1132         }
1133         GL_Clear(GL_STENCIL_BUFFER_BIT);
1134         c_rt_clears++;
1135         // LordHavoc note: many shadow volumes reside entirely inside the world
1136         // (that is to say they are entirely bounded by their lit surfaces),
1137         // which can be optimized by handling things as an inverted light volume,
1138         // with the shadow boundaries of the world being simulated by an altered
1139         // (129) bias to stencil clearing on such lights
1140         // FIXME: generate inverted light volumes for use as shadow volumes and
1141         // optimize for them as noted above
1142 }
1143
1144 void R_Shadow_Stage_Light(int shadowtest)
1145 {
1146         rmeshstate_t m;
1147         memset(&m, 0, sizeof(m));
1148         R_Mesh_State(&m);
1149         GL_BlendFunc(GL_ONE, GL_ONE);
1150         GL_DepthMask(false);
1151         GL_DepthTest(true);
1152         qglPolygonOffset(0, 0);
1153         //qglDisable(GL_POLYGON_OFFSET_FILL);
1154         GL_Color(1, 1, 1, 1);
1155         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1156         qglDepthFunc(GL_EQUAL);
1157         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1158         qglEnable(GL_CULL_FACE);
1159         if (shadowtest)
1160                 qglEnable(GL_STENCIL_TEST);
1161         else
1162                 qglDisable(GL_STENCIL_TEST);
1163         if (gl_support_stenciltwoside)
1164                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1165         qglStencilMask(~0);
1166         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1167         // only draw light where this geometry was already rendered AND the
1168         // stencil is 128 (values other than this mean shadow)
1169         qglStencilFunc(GL_EQUAL, 128, ~0);
1170         r_shadowstage = SHADOWSTAGE_LIGHT;
1171         c_rt_lights++;
1172 }
1173
1174 void R_Shadow_Stage_End(void)
1175 {
1176         rmeshstate_t m;
1177         memset(&m, 0, sizeof(m));
1178         R_Mesh_State(&m);
1179         GL_BlendFunc(GL_ONE, GL_ZERO);
1180         GL_DepthMask(true);
1181         GL_DepthTest(true);
1182         qglPolygonOffset(0, 0);
1183         //qglDisable(GL_POLYGON_OFFSET_FILL);
1184         GL_Color(1, 1, 1, 1);
1185         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1186         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1187         qglDepthFunc(GL_LEQUAL);
1188         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1189         qglDisable(GL_STENCIL_TEST);
1190         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1191         if (gl_support_stenciltwoside)
1192                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1193         qglStencilMask(~0);
1194         qglStencilFunc(GL_ALWAYS, 128, ~0);
1195         r_shadowstage = SHADOWSTAGE_NONE;
1196 }
1197
1198 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1199 {
1200         int i, ix1, iy1, ix2, iy2;
1201         float x1, y1, x2, y2, x, y, f;
1202         vec3_t smins, smaxs;
1203         vec4_t v, v2;
1204         if (!r_shadow_scissor.integer)
1205                 return false;
1206         // if view is inside the box, just say yes it's visible
1207         if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1208         {
1209                 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1210                 return false;
1211         }
1212         for (i = 0;i < 3;i++)
1213         {
1214                 if (r_viewforward[i] >= 0)
1215                 {
1216                         v[i] = mins[i];
1217                         v2[i] = maxs[i];
1218                 }
1219                 else
1220                 {
1221                         v[i] = maxs[i];
1222                         v2[i] = mins[i];
1223                 }
1224         }
1225         f = DotProduct(r_viewforward, r_vieworigin) + 1;
1226         if (DotProduct(r_viewforward, v2) <= f)
1227         {
1228                 // entirely behind nearclip plane
1229                 return true;
1230         }
1231         if (DotProduct(r_viewforward, v) >= f)
1232         {
1233                 // entirely infront of nearclip plane
1234                 x1 = y1 = x2 = y2 = 0;
1235                 for (i = 0;i < 8;i++)
1236                 {
1237                         v[0] = (i & 1) ? mins[0] : maxs[0];
1238                         v[1] = (i & 2) ? mins[1] : maxs[1];
1239                         v[2] = (i & 4) ? mins[2] : maxs[2];
1240                         v[3] = 1.0f;
1241                         GL_TransformToScreen(v, v2);
1242                         //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]);
1243                         x = v2[0];
1244                         y = v2[1];
1245                         if (i)
1246                         {
1247                                 if (x1 > x) x1 = x;
1248                                 if (x2 < x) x2 = x;
1249                                 if (y1 > y) y1 = y;
1250                                 if (y2 < y) y2 = y;
1251                         }
1252                         else
1253                         {
1254                                 x1 = x2 = x;
1255                                 y1 = y2 = y;
1256                         }
1257                 }
1258         }
1259         else
1260         {
1261                 // clipped by nearclip plane
1262                 // this is nasty and crude...
1263                 // create viewspace bbox
1264                 for (i = 0;i < 8;i++)
1265                 {
1266                         v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1267                         v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1268                         v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1269                         v2[0] = -DotProduct(v, r_viewleft);
1270                         v2[1] = DotProduct(v, r_viewup);
1271                         v2[2] = DotProduct(v, r_viewforward);
1272                         if (i)
1273                         {
1274                                 if (smins[0] > v2[0]) smins[0] = v2[0];
1275                                 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1276                                 if (smins[1] > v2[1]) smins[1] = v2[1];
1277                                 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1278                                 if (smins[2] > v2[2]) smins[2] = v2[2];
1279                                 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1280                         }
1281                         else
1282                         {
1283                                 smins[0] = smaxs[0] = v2[0];
1284                                 smins[1] = smaxs[1] = v2[1];
1285                                 smins[2] = smaxs[2] = v2[2];
1286                         }
1287                 }
1288                 // now we have a bbox in viewspace
1289                 // clip it to the view plane
1290                 if (smins[2] < 1)
1291                         smins[2] = 1;
1292                 // return true if that culled the box
1293                 if (smins[2] >= smaxs[2])
1294                         return true;
1295                 // ok some of it is infront of the view, transform each corner back to
1296                 // worldspace and then to screenspace and make screen rect
1297                 // initialize these variables just to avoid compiler warnings
1298                 x1 = y1 = x2 = y2 = 0;
1299                 for (i = 0;i < 8;i++)
1300                 {
1301                         v2[0] = (i & 1) ? smins[0] : smaxs[0];
1302                         v2[1] = (i & 2) ? smins[1] : smaxs[1];
1303                         v2[2] = (i & 4) ? smins[2] : smaxs[2];
1304                         v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1305                         v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1306                         v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1307                         v[3] = 1.0f;
1308                         GL_TransformToScreen(v, v2);
1309                         //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]);
1310                         x = v2[0];
1311                         y = v2[1];
1312                         if (i)
1313                         {
1314                                 if (x1 > x) x1 = x;
1315                                 if (x2 < x) x2 = x;
1316                                 if (y1 > y) y1 = y;
1317                                 if (y2 < y) y2 = y;
1318                         }
1319                         else
1320                         {
1321                                 x1 = x2 = x;
1322                                 y1 = y2 = y;
1323                         }
1324                 }
1325                 /*
1326                 // this code doesn't handle boxes with any points behind view properly
1327                 x1 = 1000;x2 = -1000;
1328                 y1 = 1000;y2 = -1000;
1329                 for (i = 0;i < 8;i++)
1330                 {
1331                         v[0] = (i & 1) ? mins[0] : maxs[0];
1332                         v[1] = (i & 2) ? mins[1] : maxs[1];
1333                         v[2] = (i & 4) ? mins[2] : maxs[2];
1334                         v[3] = 1.0f;
1335                         GL_TransformToScreen(v, v2);
1336                         //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]);
1337                         if (v2[2] > 0)
1338                         {
1339                                 x = v2[0];
1340                                 y = v2[1];
1341
1342                                 if (x1 > x) x1 = x;
1343                                 if (x2 < x) x2 = x;
1344                                 if (y1 > y) y1 = y;
1345                                 if (y2 < y) y2 = y;
1346                         }
1347                 }
1348                 */
1349         }
1350         ix1 = x1 - 1.0f;
1351         iy1 = y1 - 1.0f;
1352         ix2 = x2 + 1.0f;
1353         iy2 = y2 + 1.0f;
1354         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1355         if (ix1 < r_view_x) ix1 = r_view_x;
1356         if (iy1 < r_view_y) iy1 = r_view_y;
1357         if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1358         if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1359         if (ix2 <= ix1 || iy2 <= iy1)
1360                 return true;
1361         // set up the scissor rectangle
1362         GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1363         //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1364         //qglEnable(GL_SCISSOR_TEST);
1365         c_rt_scissored++;
1366         return false;
1367 }
1368
1369 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1370 {
1371         float *color4f = varray_color4f;
1372         float dist, dot, intensity, v[3], n[3];
1373         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1374         {
1375                 Matrix4x4_Transform(m, vertex3f, v);
1376                 if ((dist = DotProduct(v, v)) < 1)
1377                 {
1378                         Matrix4x4_Transform3x3(m, normal3f, n);
1379                         if ((dot = DotProduct(n, v)) > 0)
1380                         {
1381                                 dist = sqrt(dist);
1382                                 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1383                                 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1384                                 VectorScale(lightcolor, intensity, color4f);
1385                                 color4f[3] = 1;
1386                         }
1387                         else
1388                         {
1389                                 VectorClear(color4f);
1390                                 color4f[3] = 1;
1391                         }
1392                 }
1393                 else
1394                 {
1395                         VectorClear(color4f);
1396                         color4f[3] = 1;
1397                 }
1398         }
1399 }
1400
1401 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1402 {
1403         float *color4f = varray_color4f;
1404         float dist, dot, intensity, v[3], n[3];
1405         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1406         {
1407                 Matrix4x4_Transform(m, vertex3f, v);
1408                 if ((dist = fabs(v[2])) < 1)
1409                 {
1410                         Matrix4x4_Transform3x3(m, normal3f, n);
1411                         if ((dot = DotProduct(n, v)) > 0)
1412                         {
1413                                 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1414                                 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1415                                 VectorScale(lightcolor, intensity, color4f);
1416                                 color4f[3] = 1;
1417                         }
1418                         else
1419                         {
1420                                 VectorClear(color4f);
1421                                 color4f[3] = 1;
1422                         }
1423                 }
1424                 else
1425                 {
1426                         VectorClear(color4f);
1427                         color4f[3] = 1;
1428                 }
1429         }
1430 }
1431
1432 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1433 {
1434         float *color4f = varray_color4f;
1435         float dot, intensity, v[3], n[3];
1436         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1437         {
1438                 Matrix4x4_Transform(m, vertex3f, v);
1439                 Matrix4x4_Transform3x3(m, normal3f, n);
1440                 if ((dot = DotProduct(n, v)) > 0)
1441                 {
1442                         intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1443                         VectorScale(lightcolor, intensity, color4f);
1444                         color4f[3] = 1;
1445                 }
1446                 else
1447                 {
1448                         VectorClear(color4f);
1449                         color4f[3] = 1;
1450                 }
1451         }
1452 }
1453
1454 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1455 {
1456         float *color4f = varray_color4f;
1457         float dist, intensity, v[3];
1458         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1459         {
1460                 Matrix4x4_Transform(m, vertex3f, v);
1461                 if ((dist = DotProduct(v, v)) < 1)
1462                 {
1463                         dist = sqrt(dist);
1464                         intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1465                         VectorScale(lightcolor, intensity, color4f);
1466                         color4f[3] = 1;
1467                 }
1468                 else
1469                 {
1470                         VectorClear(color4f);
1471                         color4f[3] = 1;
1472                 }
1473         }
1474 }
1475
1476 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1477 {
1478         float *color4f = varray_color4f;
1479         float dist, intensity, v[3];
1480         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1481         {
1482                 Matrix4x4_Transform(m, vertex3f, v);
1483                 if ((dist = fabs(v[2])) < 1)
1484                 {
1485                         intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1486                         VectorScale(lightcolor, intensity, color4f);
1487                         color4f[3] = 1;
1488                 }
1489                 else
1490                 {
1491                         VectorClear(color4f);
1492                         color4f[3] = 1;
1493                 }
1494         }
1495 }
1496
1497 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1498 #define USETEXMATRIX
1499
1500 #ifndef USETEXMATRIX
1501 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1502 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1503 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1504 {
1505         do
1506         {
1507                 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1508                 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1509                 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1510                 vertex3f += 3;
1511                 tc3f += 3;
1512         }
1513         while (--numverts);
1514 }
1515
1516 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1517 {
1518         do
1519         {
1520                 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1521                 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1522                 vertex3f += 3;
1523                 tc2f += 2;
1524         }
1525         while (--numverts);
1526 }
1527 #endif
1528
1529 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
1530 {
1531         int i;
1532         float lightdir[3];
1533         for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1534         {
1535                 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1536                 // the cubemap normalizes this for us
1537                 out3f[0] = DotProduct(svector3f, lightdir);
1538                 out3f[1] = DotProduct(tvector3f, lightdir);
1539                 out3f[2] = DotProduct(normal3f, lightdir);
1540         }
1541 }
1542
1543 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
1544 {
1545         int i;
1546         float lightdir[3], eyedir[3], halfdir[3];
1547         for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1548         {
1549                 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1550                 VectorNormalizeFast(lightdir);
1551                 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1552                 VectorNormalizeFast(eyedir);
1553                 VectorAdd(lightdir, eyedir, halfdir);
1554                 // the cubemap normalizes this for us
1555                 out3f[0] = DotProduct(svector3f, halfdir);
1556                 out3f[1] = DotProduct(tvector3f, halfdir);
1557                 out3f[2] = DotProduct(normal3f, halfdir);
1558         }
1559 }
1560
1561 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int visiblelighting)
1562 {
1563         int renders;
1564         float color[3], color2[3], colorscale;
1565         rmeshstate_t m;
1566         if (!basetexture)
1567                 basetexture = r_texture_white;
1568         if (!bumptexture)
1569                 bumptexture = r_texture_blanknormalmap;
1570         if (!lightcolorbase)
1571                 lightcolorbase = vec3_origin;
1572         if (!lightcolorpants)
1573                 lightcolorpants = vec3_origin;
1574         if (!lightcolorshirt)
1575                 lightcolorshirt = vec3_origin;
1576         specularscale *= r_shadow_glossintensity.value;
1577         if (!glosstexture)
1578         {
1579                 if (r_shadow_gloss.integer >= 2)
1580                 {
1581                         glosstexture = r_texture_white;
1582                         specularscale *= r_shadow_gloss2intensity.value;
1583                 }
1584                 else
1585                 {
1586                         glosstexture = r_texture_black;
1587                         specularscale = 0;
1588                 }
1589         }
1590         if (r_shadow_gloss.integer < 1)
1591                 specularscale = 0;
1592         if (!lightcubemap)
1593                 lightcubemap = r_shadow_blankwhitecubetexture;
1594         if ((ambientscale + diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1595                 return;
1596         if (visiblelighting)
1597         {
1598                 int passes = 0;
1599                 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1600                         passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1601                 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1602                 {
1603                         // TODO: add direct pants/shirt rendering
1604                         if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1605                                 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1606                         if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1607                                 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1608                         if (!bumptexture)
1609                                 bumptexture = r_texture_blanknormalmap;
1610                         if (!glosstexture)
1611                                 glosstexture = r_texture_white;
1612                         if (ambientscale)
1613                         {
1614                                 colorscale = ambientscale;
1615                                 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1616                                 {
1617                                 }
1618                                 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1619                                 {
1620                                 }
1621                                 else if (r_textureunits.integer >= 4 && lightcubemap)
1622                                 {
1623                                 }
1624                                 else if (r_textureunits.integer >= 3 && !lightcubemap)
1625                                 {
1626                                 }
1627                                 else
1628                                         passes++;
1629                                 VectorScale(lightcolorbase, colorscale, color2);
1630                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1631                                         passes++;
1632                         }
1633                         if (diffusescale)
1634                         {
1635                                 colorscale = diffusescale;
1636                                 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1637                                 {
1638                                         // 3/2 3D combine path (Geforce3, Radeon 8500)
1639                                         passes++;
1640                                 }
1641                                 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1642                                 {
1643                                         // 1/2/2 3D combine path (original Radeon)
1644                                         passes += 2;
1645                                 }
1646                                 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1647                                 {
1648                                         // 2/2 3D combine path (original Radeon)
1649                                         passes++;
1650                                 }
1651                                 else if (r_textureunits.integer >= 4)
1652                                 {
1653                                         // 4/2 2D combine path (Geforce3, Radeon 8500)
1654                                         passes++;
1655                                 }
1656                                 else
1657                                 {
1658                                         // 2/2/2 2D combine path (any dot3 card)
1659                                         passes += 2;
1660                                 }
1661                                 VectorScale(lightcolorbase, colorscale, color2);
1662                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1663                                         passes++;
1664                         }
1665                         if (specularscale && glosstexture != r_texture_black)
1666                         {
1667                                 //if (gl_support_blendsquare)
1668                                 {
1669                                         colorscale = specularscale;
1670                                         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1671                                                 passes += 4;
1672                                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1673                                                 passes += 3;
1674                                         else
1675                                                 passes += 4;
1676                                         VectorScale(lightcolorbase, colorscale, color2);
1677                                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1678                                                 passes++;
1679                                 }
1680                         }
1681                 }
1682                 else
1683                 {
1684                         // TODO: add direct pants/shirt rendering
1685                         if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1686                                 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1687                         if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1688                                 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1689                         if (ambientscale)
1690                         {
1691                                 VectorScale(lightcolorbase, ambientscale, color2);
1692                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1693                                         passes++;
1694                         }
1695                         if (diffusescale)
1696                         {
1697                                 VectorScale(lightcolorbase, diffusescale, color2);
1698                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1699                                         passes++;
1700                         }
1701                 }
1702                 if (passes)
1703                 {
1704                         GL_Color(0.1*passes, 0.025*passes, 0, 1);
1705                         memset(&m, 0, sizeof(m));
1706                         m.pointer_vertex = vertex3f;
1707                         R_Mesh_State(&m);
1708                         GL_LockArrays(firstvertex, numvertices);
1709                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1710                         GL_LockArrays(0, 0);
1711                 }
1712                 return;
1713         }
1714         // FIXME: support EF_NODEPTHTEST
1715         GL_DepthMask(false);
1716         GL_DepthTest(true);
1717         if (r_shadow_glsl.integer && r_shadow_program_light[0])
1718         {
1719                 unsigned int perm, prog;
1720                 // GLSL shader path (GFFX5200, Radeon 9500)
1721                 memset(&m, 0, sizeof(m));
1722                 m.pointer_vertex = vertex3f;
1723                 m.pointer_texcoord[0] = texcoord2f;
1724                 m.pointer_texcoord3f[1] = svector3f;
1725                 m.pointer_texcoord3f[2] = tvector3f;
1726                 m.pointer_texcoord3f[3] = normal3f;
1727                 m.tex[0] = R_GetTexture(bumptexture);
1728                 m.tex[1] = R_GetTexture(basetexture);
1729                 m.tex[2] = R_GetTexture(glosstexture);
1730                 m.texcubemap[3] = R_GetTexture(lightcubemap);
1731                 // TODO: support fog (after renderer is converted to texture fog)
1732                 m.tex[4] = R_GetTexture(r_texture_white);
1733                 m.texmatrix[3] = *matrix_modeltolight;
1734                 R_Mesh_State(&m);
1735                 GL_BlendFunc(GL_ONE, GL_ONE);
1736                 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1737                 CHECKGLERROR
1738                 perm = 0;
1739                 // only add a feature to the permutation if that permutation exists
1740                 // (otherwise it might end up not using a shader at all, which looks
1741                 // worse than using less features)
1742                 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1743                         perm |= SHADERPERMUTATION_SPECULAR;
1744                 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1745                 //      perm |= SHADERPERMUTATION_FOG;
1746                 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1747                         perm |= SHADERPERMUTATION_CUBEFILTER;
1748                 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1749                         perm |= SHADERPERMUTATION_OFFSETMAPPING;
1750                 prog = r_shadow_program_light[perm];
1751                 qglUseProgramObjectARB(prog);CHECKGLERROR
1752                 // TODO: support fog (after renderer is converted to texture fog)
1753                 if (perm & SHADERPERMUTATION_FOG)
1754                 {
1755                         qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1756                 }
1757                 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1758                 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1759                 if (perm & SHADERPERMUTATION_SPECULAR)
1760                 {
1761                         qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1762                         qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1763                 }
1764                 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1765                 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1766                 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1767                 {
1768                         qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1769                 }
1770                 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1771                 {
1772                         qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1773                         qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1774                 }
1775                 CHECKGLERROR
1776                 GL_LockArrays(firstvertex, numvertices);
1777                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1778                 c_rt_lightmeshes++;
1779                 c_rt_lighttris += numtriangles;
1780                 // TODO: add direct pants/shirt rendering
1781                 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1782                 {
1783                         R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1784                         qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1785                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1786                         c_rt_lightmeshes++;
1787                         c_rt_lighttris += numtriangles;
1788                 }
1789                 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1790                 {
1791                         R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1792                         qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1793                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1794                         c_rt_lightmeshes++;
1795                         c_rt_lighttris += numtriangles;
1796                 }
1797                 GL_LockArrays(0, 0);
1798                 qglUseProgramObjectARB(0);
1799                 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1800                 qglBegin(GL_TRIANGLES);
1801                 qglEnd();
1802                 CHECKGLERROR
1803         }
1804         else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1805         {
1806                 // TODO: add direct pants/shirt rendering
1807                 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1808                         R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1809                 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1810                         R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1811                 if (!bumptexture)
1812                         bumptexture = r_texture_blanknormalmap;
1813                 if (!glosstexture)
1814                         glosstexture = r_texture_white;
1815                 if (ambientscale)
1816                 {
1817                         GL_Color(1,1,1,1);
1818                         colorscale = ambientscale;
1819                         // colorscale accounts for how much we multiply the brightness
1820                         // during combine.
1821                         //
1822                         // mult is how many times the final pass of the lighting will be
1823                         // performed to get more brightness than otherwise possible.
1824                         //
1825                         // Limit mult to 64 for sanity sake.
1826                         if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1827                         {
1828                                 // 3 3D combine path (Geforce3, Radeon 8500)
1829                                 memset(&m, 0, sizeof(m));
1830                                 m.pointer_vertex = vertex3f;
1831                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1832 #ifdef USETEXMATRIX
1833                                 m.pointer_texcoord3f[0] = vertex3f;
1834                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1835 #else
1836                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1837                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1838 #endif
1839                                 m.tex[1] = R_GetTexture(basetexture);
1840                                 m.pointer_texcoord[1] = texcoord2f;
1841                                 m.texcubemap[2] = R_GetTexture(lightcubemap);
1842 #ifdef USETEXMATRIX
1843                                 m.pointer_texcoord3f[2] = vertex3f;
1844                                 m.texmatrix[2] = *matrix_modeltolight;
1845 #else
1846                                 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1847                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1848 #endif
1849                                 GL_BlendFunc(GL_ONE, GL_ONE);
1850                         }
1851                         else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1852                         {
1853                                 // 2 3D combine path (Geforce3, original Radeon)
1854                                 memset(&m, 0, sizeof(m));
1855                                 m.pointer_vertex = vertex3f;
1856                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1857 #ifdef USETEXMATRIX
1858                                 m.pointer_texcoord3f[0] = vertex3f;
1859                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1860 #else
1861                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1862                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1863 #endif
1864                                 m.tex[1] = R_GetTexture(basetexture);
1865                                 m.pointer_texcoord[1] = texcoord2f;
1866                                 GL_BlendFunc(GL_ONE, GL_ONE);
1867                         }
1868                         else if (r_textureunits.integer >= 4 && lightcubemap)
1869                         {
1870                                 // 4 2D combine path (Geforce3, Radeon 8500)
1871                                 memset(&m, 0, sizeof(m));
1872                                 m.pointer_vertex = vertex3f;
1873                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1874 #ifdef USETEXMATRIX
1875                                 m.pointer_texcoord3f[0] = vertex3f;
1876                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1877 #else
1878                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1879                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1880 #endif
1881                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1882 #ifdef USETEXMATRIX
1883                                 m.pointer_texcoord3f[1] = vertex3f;
1884                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1885 #else
1886                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1887                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1888 #endif
1889                                 m.tex[2] = R_GetTexture(basetexture);
1890                                 m.pointer_texcoord[2] = texcoord2f;
1891                                 if (lightcubemap)
1892                                 {
1893                                         m.texcubemap[3] = R_GetTexture(lightcubemap);
1894 #ifdef USETEXMATRIX
1895                                         m.pointer_texcoord3f[3] = vertex3f;
1896                                         m.texmatrix[3] = *matrix_modeltolight;
1897 #else
1898                                         m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1899                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1900 #endif
1901                                 }
1902                                 GL_BlendFunc(GL_ONE, GL_ONE);
1903                         }
1904                         else if (r_textureunits.integer >= 3 && !lightcubemap)
1905                         {
1906                                 // 3 2D combine path (Geforce3, original Radeon)
1907                                 memset(&m, 0, sizeof(m));
1908                                 m.pointer_vertex = vertex3f;
1909                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1910 #ifdef USETEXMATRIX
1911                                 m.pointer_texcoord3f[0] = vertex3f;
1912                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1913 #else
1914                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1915                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1916 #endif
1917                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1918 #ifdef USETEXMATRIX
1919                                 m.pointer_texcoord3f[1] = vertex3f;
1920                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1921 #else
1922                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1923                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1924 #endif
1925                                 m.tex[2] = R_GetTexture(basetexture);
1926                                 m.pointer_texcoord[2] = texcoord2f;
1927                                 GL_BlendFunc(GL_ONE, GL_ONE);
1928                         }
1929                         else
1930                         {
1931                                 // 2/2/2 2D combine path (any dot3 card)
1932                                 memset(&m, 0, sizeof(m));
1933                                 m.pointer_vertex = vertex3f;
1934                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1935 #ifdef USETEXMATRIX
1936                                 m.pointer_texcoord3f[0] = vertex3f;
1937                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1938 #else
1939                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1940                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1941 #endif
1942                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1943 #ifdef USETEXMATRIX
1944                                 m.pointer_texcoord3f[1] = vertex3f;
1945                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1946 #else
1947                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1948                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1949 #endif
1950                                 R_Mesh_State(&m);
1951                                 GL_ColorMask(0,0,0,1);
1952                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1953                                 GL_LockArrays(firstvertex, numvertices);
1954                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1955                                 GL_LockArrays(0, 0);
1956                                 c_rt_lightmeshes++;
1957                                 c_rt_lighttris += numtriangles;
1958
1959                                 memset(&m, 0, sizeof(m));
1960                                 m.pointer_vertex = vertex3f;
1961                                 m.tex[0] = R_GetTexture(basetexture);
1962                                 m.pointer_texcoord[0] = texcoord2f;
1963                                 if (lightcubemap)
1964                                 {
1965                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1966 #ifdef USETEXMATRIX
1967                                         m.pointer_texcoord3f[1] = vertex3f;
1968                                         m.texmatrix[1] = *matrix_modeltolight;
1969 #else
1970                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1971                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1972 #endif
1973                                 }
1974                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1975                         }
1976                         // this final code is shared
1977                         R_Mesh_State(&m);
1978                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1979                         VectorScale(lightcolorbase, colorscale, color2);
1980                         GL_LockArrays(firstvertex, numvertices);
1981                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1982                         {
1983                                 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1984                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1985                                 c_rt_lightmeshes++;
1986                                 c_rt_lighttris += numtriangles;
1987                         }
1988                         GL_LockArrays(0, 0);
1989                 }
1990                 if (diffusescale)
1991                 {
1992                         GL_Color(1,1,1,1);
1993                         colorscale = diffusescale;
1994                         // colorscale accounts for how much we multiply the brightness
1995                         // during combine.
1996                         //
1997                         // mult is how many times the final pass of the lighting will be
1998                         // performed to get more brightness than otherwise possible.
1999                         //
2000                         // Limit mult to 64 for sanity sake.
2001                         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2002                         {
2003                                 // 3/2 3D combine path (Geforce3, Radeon 8500)
2004                                 memset(&m, 0, sizeof(m));
2005                                 m.pointer_vertex = vertex3f;
2006                                 m.tex[0] = R_GetTexture(bumptexture);
2007                                 m.texcombinergb[0] = GL_REPLACE;
2008                                 m.pointer_texcoord[0] = texcoord2f;
2009                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2010                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2011                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2012                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2013                                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2014 #ifdef USETEXMATRIX
2015                                 m.pointer_texcoord3f[2] = vertex3f;
2016                                 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2017 #else
2018                                 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
2019                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2020 #endif
2021                                 R_Mesh_State(&m);
2022                                 GL_ColorMask(0,0,0,1);
2023                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2024                                 GL_LockArrays(firstvertex, numvertices);
2025                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2026                                 GL_LockArrays(0, 0);
2027                                 c_rt_lightmeshes++;
2028                                 c_rt_lighttris += numtriangles;
2029
2030                                 memset(&m, 0, sizeof(m));
2031                                 m.pointer_vertex = vertex3f;
2032                                 m.tex[0] = R_GetTexture(basetexture);
2033                                 m.pointer_texcoord[0] = texcoord2f;
2034                                 if (lightcubemap)
2035                                 {
2036                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
2037 #ifdef USETEXMATRIX
2038                                         m.pointer_texcoord3f[1] = vertex3f;
2039                                         m.texmatrix[1] = *matrix_modeltolight;
2040 #else
2041                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2042                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2043 #endif
2044                                 }
2045                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2046                         }
2047                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
2048                         {
2049                                 // 1/2/2 3D combine path (original Radeon)
2050                                 memset(&m, 0, sizeof(m));
2051                                 m.pointer_vertex = vertex3f;
2052                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2053 #ifdef USETEXMATRIX
2054                                 m.pointer_texcoord3f[0] = vertex3f;
2055                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2056 #else
2057                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2058                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2059 #endif
2060                                 R_Mesh_State(&m);
2061                                 GL_ColorMask(0,0,0,1);
2062                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2063                                 GL_LockArrays(firstvertex, numvertices);
2064                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2065                                 GL_LockArrays(0, 0);
2066                                 c_rt_lightmeshes++;
2067                                 c_rt_lighttris += numtriangles;
2068
2069                                 memset(&m, 0, sizeof(m));
2070                                 m.pointer_vertex = vertex3f;
2071                                 m.tex[0] = R_GetTexture(bumptexture);
2072                                 m.texcombinergb[0] = GL_REPLACE;
2073                                 m.pointer_texcoord[0] = texcoord2f;
2074                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2075                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2076                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2077                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2078                                 R_Mesh_State(&m);
2079                                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2080                                 GL_LockArrays(firstvertex, numvertices);
2081                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2082                                 GL_LockArrays(0, 0);
2083                                 c_rt_lightmeshes++;
2084                                 c_rt_lighttris += numtriangles;
2085
2086                                 memset(&m, 0, sizeof(m));
2087                                 m.pointer_vertex = vertex3f;
2088                                 m.tex[0] = R_GetTexture(basetexture);
2089                                 m.pointer_texcoord[0] = texcoord2f;
2090                                 if (lightcubemap)
2091                                 {
2092                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
2093 #ifdef USETEXMATRIX
2094                                         m.pointer_texcoord3f[1] = vertex3f;
2095                                         m.texmatrix[1] = *matrix_modeltolight;
2096 #else
2097                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2098                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2099 #endif
2100                                 }
2101                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2102                         }
2103                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
2104                         {
2105                                 // 2/2 3D combine path (original Radeon)
2106                                 memset(&m, 0, sizeof(m));
2107                                 m.pointer_vertex = vertex3f;
2108                                 m.tex[0] = R_GetTexture(bumptexture);
2109                                 m.texcombinergb[0] = GL_REPLACE;
2110                                 m.pointer_texcoord[0] = texcoord2f;
2111                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2112                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2113                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2114                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2115                                 R_Mesh_State(&m);
2116                                 GL_ColorMask(0,0,0,1);
2117                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2118                                 GL_LockArrays(firstvertex, numvertices);
2119                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2120                                 GL_LockArrays(0, 0);
2121                                 c_rt_lightmeshes++;
2122                                 c_rt_lighttris += numtriangles;
2123
2124                                 memset(&m, 0, sizeof(m));
2125                                 m.pointer_vertex = vertex3f;
2126                                 m.tex[0] = R_GetTexture(basetexture);
2127                                 m.pointer_texcoord[0] = texcoord2f;
2128                                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2129 #ifdef USETEXMATRIX
2130                                 m.pointer_texcoord3f[1] = vertex3f;
2131                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2132 #else
2133                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2134                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2135 #endif
2136                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2137                         }
2138                         else if (r_textureunits.integer >= 4)
2139                         {
2140                                 // 4/2 2D combine path (Geforce3, Radeon 8500)
2141                                 memset(&m, 0, sizeof(m));
2142                                 m.pointer_vertex = vertex3f;
2143                                 m.tex[0] = R_GetTexture(bumptexture);
2144                                 m.texcombinergb[0] = GL_REPLACE;
2145                                 m.pointer_texcoord[0] = texcoord2f;
2146                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2147                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2148                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2149                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2150                                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2151 #ifdef USETEXMATRIX
2152                                 m.pointer_texcoord3f[2] = vertex3f;
2153                                 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2154 #else
2155                                 m.pointer_texcoord[2] = varray_texcoord2f[2];
2156                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2157 #endif
2158                                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2159 #ifdef USETEXMATRIX
2160                                 m.pointer_texcoord3f[3] = vertex3f;
2161                                 m.texmatrix[3] = *matrix_modeltoattenuationz;
2162 #else
2163                                 m.pointer_texcoord[3] = varray_texcoord2f[3];
2164                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2165 #endif
2166                                 R_Mesh_State(&m);
2167                                 GL_ColorMask(0,0,0,1);
2168                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2169                                 GL_LockArrays(firstvertex, numvertices);
2170                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2171                                 GL_LockArrays(0, 0);
2172                                 c_rt_lightmeshes++;
2173                                 c_rt_lighttris += numtriangles;
2174
2175                                 memset(&m, 0, sizeof(m));
2176                                 m.pointer_vertex = vertex3f;
2177                                 m.tex[0] = R_GetTexture(basetexture);
2178                                 m.pointer_texcoord[0] = texcoord2f;
2179                                 if (lightcubemap)
2180                                 {
2181                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
2182 #ifdef USETEXMATRIX
2183                                         m.pointer_texcoord3f[1] = vertex3f;
2184                                         m.texmatrix[1] = *matrix_modeltolight;
2185 #else
2186                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2187                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2188 #endif
2189                                 }
2190                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2191                         }
2192                         else
2193                         {
2194                                 // 2/2/2 2D combine path (any dot3 card)
2195                                 memset(&m, 0, sizeof(m));
2196                                 m.pointer_vertex = vertex3f;
2197                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2198 #ifdef USETEXMATRIX
2199                                 m.pointer_texcoord3f[0] = vertex3f;
2200                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2201 #else
2202                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
2203                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2204 #endif
2205                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2206 #ifdef USETEXMATRIX
2207                                 m.pointer_texcoord3f[1] = vertex3f;
2208                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
2209 #else
2210                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2211                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2212 #endif
2213                                 R_Mesh_State(&m);
2214                                 GL_ColorMask(0,0,0,1);
2215                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2216                                 GL_LockArrays(firstvertex, numvertices);
2217                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2218                                 GL_LockArrays(0, 0);
2219                                 c_rt_lightmeshes++;
2220                                 c_rt_lighttris += numtriangles;
2221
2222                                 memset(&m, 0, sizeof(m));
2223                                 m.pointer_vertex = vertex3f;
2224                                 m.tex[0] = R_GetTexture(bumptexture);
2225                                 m.texcombinergb[0] = GL_REPLACE;
2226                                 m.pointer_texcoord[0] = texcoord2f;
2227                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2228                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2229                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2230                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2231                                 R_Mesh_State(&m);
2232                                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2233                                 GL_LockArrays(firstvertex, numvertices);
2234                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2235                                 GL_LockArrays(0, 0);
2236                                 c_rt_lightmeshes++;
2237                                 c_rt_lighttris += numtriangles;
2238
2239                                 memset(&m, 0, sizeof(m));
2240                                 m.pointer_vertex = vertex3f;
2241                                 m.tex[0] = R_GetTexture(basetexture);
2242                                 m.pointer_texcoord[0] = texcoord2f;
2243                                 if (lightcubemap)
2244                                 {
2245                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
2246 #ifdef USETEXMATRIX
2247                                         m.pointer_texcoord3f[1] = vertex3f;
2248                                         m.texmatrix[1] = *matrix_modeltolight;
2249 #else
2250                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2251                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2252 #endif
2253                                 }
2254                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2255                         }
2256                         // this final code is shared
2257                         R_Mesh_State(&m);
2258                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2259                         VectorScale(lightcolorbase, colorscale, color2);
2260                         GL_LockArrays(firstvertex, numvertices);
2261                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2262                         {
2263                                 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2264                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2265                                 c_rt_lightmeshes++;
2266                                 c_rt_lighttris += numtriangles;
2267                         }
2268                         GL_LockArrays(0, 0);
2269                 }
2270                 if (specularscale && glosstexture != r_texture_black)
2271                 {
2272                         // FIXME: detect blendsquare!
2273                         //if (gl_support_blendsquare)
2274                         {
2275                                 colorscale = specularscale;
2276                                 GL_Color(1,1,1,1);
2277                                 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2278                                 {
2279                                         // 2/0/0/1/2 3D combine blendsquare path
2280                                         memset(&m, 0, sizeof(m));
2281                                         m.pointer_vertex = vertex3f;
2282                                         m.tex[0] = R_GetTexture(bumptexture);
2283                                         m.pointer_texcoord[0] = texcoord2f;
2284                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2285                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2286                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2287                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2288                                         R_Mesh_State(&m);
2289                                         GL_ColorMask(0,0,0,1);
2290                                         // this squares the result
2291                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2292                                         GL_LockArrays(firstvertex, numvertices);
2293                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2294                                         GL_LockArrays(0, 0);
2295                                         c_rt_lightmeshes++;
2296                                         c_rt_lighttris += numtriangles;
2297
2298                                         memset(&m, 0, sizeof(m));
2299                                         m.pointer_vertex = vertex3f;
2300                                         R_Mesh_State(&m);
2301                                         GL_LockArrays(firstvertex, numvertices);
2302                                         // square alpha in framebuffer a few times to make it shiny
2303                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2304                                         // these comments are a test run through this math for intensity 0.5
2305                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2306                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2307                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2308                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2309                                         c_rt_lightmeshes++;
2310                                         c_rt_lighttris += numtriangles;
2311                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2312                                         c_rt_lightmeshes++;
2313                                         c_rt_lighttris += numtriangles;
2314                                         GL_LockArrays(0, 0);
2315
2316                                         memset(&m, 0, sizeof(m));
2317                                         m.pointer_vertex = vertex3f;
2318                                         m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2319 #ifdef USETEXMATRIX
2320                                         m.pointer_texcoord3f[0] = vertex3f;
2321                                         m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2322 #else
2323                                         m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2324                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2325 #endif
2326                                         R_Mesh_State(&m);
2327                                         GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2328                                         GL_LockArrays(firstvertex, numvertices);
2329                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2330                                         GL_LockArrays(0, 0);
2331                                         c_rt_lightmeshes++;
2332                                         c_rt_lighttris += numtriangles;
2333
2334                                         memset(&m, 0, sizeof(m));
2335                                         m.pointer_vertex = vertex3f;
2336                                         m.tex[0] = R_GetTexture(glosstexture);
2337                                         m.pointer_texcoord[0] = texcoord2f;
2338                                         if (lightcubemap)
2339                                         {
2340                                                 m.texcubemap[1] = R_GetTexture(lightcubemap);
2341 #ifdef USETEXMATRIX
2342                                                 m.pointer_texcoord3f[1] = vertex3f;
2343                                                 m.texmatrix[1] = *matrix_modeltolight;
2344 #else
2345                                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2346                                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2347 #endif
2348                                         }
2349                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2350                                 }
2351                                 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2352                                 {
2353                                         // 2/0/0/2 3D combine blendsquare path
2354                                         memset(&m, 0, sizeof(m));
2355                                         m.pointer_vertex = vertex3f;
2356                                         m.tex[0] = R_GetTexture(bumptexture);
2357                                         m.pointer_texcoord[0] = texcoord2f;
2358                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2359                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2360                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2361                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2362                                         R_Mesh_State(&m);
2363                                         GL_ColorMask(0,0,0,1);
2364                                         // this squares the result
2365                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2366                                         GL_LockArrays(firstvertex, numvertices);
2367                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2368                                         GL_LockArrays(0, 0);
2369                                         c_rt_lightmeshes++;
2370                                         c_rt_lighttris += numtriangles;
2371
2372                                         memset(&m, 0, sizeof(m));
2373                                         m.pointer_vertex = vertex3f;
2374                                         R_Mesh_State(&m);
2375                                         GL_LockArrays(firstvertex, numvertices);
2376                                         // square alpha in framebuffer a few times to make it shiny
2377                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2378                                         // these comments are a test run through this math for intensity 0.5
2379                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2380                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2381                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2382                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2383                                         c_rt_lightmeshes++;
2384                                         c_rt_lighttris += numtriangles;
2385                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2386                                         c_rt_lightmeshes++;
2387                                         c_rt_lighttris += numtriangles;
2388                                         GL_LockArrays(0, 0);
2389
2390                                         memset(&m, 0, sizeof(m));
2391                                         m.pointer_vertex = vertex3f;
2392                                         m.tex[0] = R_GetTexture(glosstexture);
2393                                         m.pointer_texcoord[0] = texcoord2f;
2394                                         m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2395 #ifdef USETEXMATRIX
2396                                         m.pointer_texcoord3f[1] = vertex3f;
2397                                         m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2398 #else
2399                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2400                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2401 #endif
2402                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2403                                 }
2404                                 else
2405                                 {
2406                                         // 2/0/0/2/2 2D combine blendsquare path
2407                                         memset(&m, 0, sizeof(m));
2408                                         m.pointer_vertex = vertex3f;
2409                                         m.tex[0] = R_GetTexture(bumptexture);
2410                                         m.pointer_texcoord[0] = texcoord2f;
2411                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2412                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2413                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2414                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2415                                         R_Mesh_State(&m);
2416                                         GL_ColorMask(0,0,0,1);
2417                                         // this squares the result
2418                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2419                                         GL_LockArrays(firstvertex, numvertices);
2420                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2421                                         GL_LockArrays(0, 0);
2422                                         c_rt_lightmeshes++;
2423                                         c_rt_lighttris += numtriangles;
2424
2425                                         memset(&m, 0, sizeof(m));
2426                                         m.pointer_vertex = vertex3f;
2427                                         R_Mesh_State(&m);
2428                                         GL_LockArrays(firstvertex, numvertices);
2429                                         // square alpha in framebuffer a few times to make it shiny
2430                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2431                                         // these comments are a test run through this math for intensity 0.5
2432                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2433                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2434                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2435                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2436                                         c_rt_lightmeshes++;
2437                                         c_rt_lighttris += numtriangles;
2438                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2439                                         c_rt_lightmeshes++;
2440                                         c_rt_lighttris += numtriangles;
2441                                         GL_LockArrays(0, 0);
2442
2443                                         memset(&m, 0, sizeof(m));
2444                                         m.pointer_vertex = vertex3f;
2445                                         m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2446 #ifdef USETEXMATRIX
2447                                         m.pointer_texcoord3f[0] = vertex3f;
2448                                         m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2449 #else
2450                                         m.pointer_texcoord[0] = varray_texcoord2f[0];
2451                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2452 #endif
2453                                         m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2454 #ifdef USETEXMATRIX
2455                                         m.pointer_texcoord3f[1] = vertex3f;
2456                                         m.texmatrix[1] = *matrix_modeltoattenuationz;
2457 #else
2458                                         m.pointer_texcoord[1] = varray_texcoord2f[1];
2459                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2460 #endif
2461                                         R_Mesh_State(&m);
2462                                         GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2463                                         GL_LockArrays(firstvertex, numvertices);
2464                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2465                                         GL_LockArrays(0, 0);
2466                                         c_rt_lightmeshes++;
2467                                         c_rt_lighttris += numtriangles;
2468
2469                                         memset(&m, 0, sizeof(m));
2470                                         m.pointer_vertex = vertex3f;
2471                                         m.tex[0] = R_GetTexture(glosstexture);
2472                                         m.pointer_texcoord[0] = texcoord2f;
2473                                         if (lightcubemap)
2474                                         {
2475                                                 m.texcubemap[1] = R_GetTexture(lightcubemap);
2476 #ifdef USETEXMATRIX
2477                                                 m.pointer_texcoord3f[1] = vertex3f;
2478                                                 m.texmatrix[1] = *matrix_modeltolight;
2479 #else
2480                                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2481                                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2482 #endif
2483                                         }
2484                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2485                                 }
2486                                 R_Mesh_State(&m);
2487                                 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2488                                 VectorScale(lightcolorbase, colorscale, color2);
2489                                 GL_LockArrays(firstvertex, numvertices);
2490                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2491                                 {
2492                                         GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2493                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2494                                         c_rt_lightmeshes++;
2495                                         c_rt_lighttris += numtriangles;
2496                                 }
2497                                 GL_LockArrays(0, 0);
2498                         }
2499                 }
2500         }
2501         else
2502         {
2503                 // TODO: add direct pants/shirt rendering
2504                 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2505                         R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
2506                 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2507                         R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
2508                 if (ambientscale)
2509                 {
2510                         GL_BlendFunc(GL_ONE, GL_ONE);
2511                         VectorScale(lightcolorbase, ambientscale, color2);
2512                         memset(&m, 0, sizeof(m));
2513                         m.pointer_vertex = vertex3f;
2514                         m.tex[0] = R_GetTexture(basetexture);
2515                         m.pointer_texcoord[0] = texcoord2f;
2516                         if (r_textureunits.integer >= 2)
2517                         {
2518                                 // voodoo2
2519                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2520 #ifdef USETEXMATRIX
2521                                 m.pointer_texcoord3f[1] = vertex3f;
2522                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2523 #else
2524                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2525                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2526 #endif
2527                                 if (r_textureunits.integer >= 3)
2528                                 {
2529                                         // Geforce3/Radeon class but not using dot3
2530                                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2531 #ifdef USETEXMATRIX
2532                                         m.pointer_texcoord3f[2] = vertex3f;
2533                                         m.texmatrix[2] = *matrix_modeltoattenuationz;
2534 #else
2535                                         m.pointer_texcoord[2] = varray_texcoord2f[2];
2536                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2537 #endif
2538                                 }
2539                         }
2540                         if (r_textureunits.integer >= 3)
2541                                 m.pointer_color = NULL;
2542                         else
2543                                 m.pointer_color = varray_color4f;
2544                         R_Mesh_State(&m);
2545                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2546                         {
2547                                 color[0] = bound(0, color2[0], 1);
2548                                 color[1] = bound(0, color2[1], 1);
2549                                 color[2] = bound(0, color2[2], 1);
2550                                 if (r_textureunits.integer >= 3)
2551                                         GL_Color(color[0], color[1], color[2], 1);
2552                                 else if (r_textureunits.integer >= 2)
2553                                         R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2554                                 else
2555                                         R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2556                                 GL_LockArrays(firstvertex, numvertices);
2557                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2558                                 GL_LockArrays(0, 0);
2559                                 c_rt_lightmeshes++;
2560                                 c_rt_lighttris += numtriangles;
2561                         }
2562                 }
2563                 if (diffusescale)
2564                 {
2565                         GL_BlendFunc(GL_ONE, GL_ONE);
2566                         VectorScale(lightcolorbase, diffusescale, color2);
2567                         memset(&m, 0, sizeof(m));
2568                         m.pointer_vertex = vertex3f;
2569                         m.pointer_color = varray_color4f;
2570                         m.tex[0] = R_GetTexture(basetexture);
2571                         m.pointer_texcoord[0] = texcoord2f;
2572                         if (r_textureunits.integer >= 2)
2573                         {
2574                                 // voodoo2
2575                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2576 #ifdef USETEXMATRIX
2577                                 m.pointer_texcoord3f[1] = vertex3f;
2578                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2579 #else
2580                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2581                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2582 #endif
2583                                 if (r_textureunits.integer >= 3)
2584                                 {
2585                                         // Geforce3/Radeon class but not using dot3
2586                                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2587 #ifdef USETEXMATRIX
2588                                         m.pointer_texcoord3f[2] = vertex3f;
2589                                         m.texmatrix[2] = *matrix_modeltoattenuationz;
2590 #else
2591                                         m.pointer_texcoord[2] = varray_texcoord2f[2];
2592                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2593 #endif
2594                                 }
2595                         }
2596                         R_Mesh_State(&m);
2597                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2598                         {
2599                                 color[0] = bound(0, color2[0], 1);
2600                                 color[1] = bound(0, color2[1], 1);
2601                                 color[2] = bound(0, color2[2], 1);
2602                                 if (r_textureunits.integer >= 3)
2603                                         R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2604                                 else if (r_textureunits.integer >= 2)
2605                                         R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2606                                 else
2607                                         R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2608                                 GL_LockArrays(firstvertex, numvertices);
2609                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2610                                 GL_LockArrays(0, 0);
2611                                 c_rt_lightmeshes++;
2612                                 c_rt_lighttris += numtriangles;
2613                         }
2614                 }
2615         }
2616 }
2617
2618 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2619 {
2620         int j, k;
2621         float scale;
2622         R_RTLight_Uncompile(rtlight);
2623         memset(rtlight, 0, sizeof(*rtlight));
2624
2625         VectorCopy(light->origin, rtlight->shadoworigin);
2626         VectorCopy(light->color, rtlight->color);
2627         rtlight->radius = light->radius;
2628         //rtlight->cullradius = rtlight->radius;
2629         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2630         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2631         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2632         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2633         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2634         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2635         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2636         rtlight->cubemapname[0] = 0;
2637         if (light->cubemapname[0])
2638                 strcpy(rtlight->cubemapname, light->cubemapname);
2639         else if (light->cubemapnum > 0)
2640                 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2641         rtlight->shadow = light->shadow;
2642         rtlight->corona = light->corona;
2643         rtlight->style = light->style;
2644         rtlight->isstatic = isstatic;
2645         rtlight->coronasizescale = light->coronasizescale;
2646         rtlight->ambientscale = light->ambientscale;
2647         rtlight->diffusescale = light->diffusescale;
2648         rtlight->specularscale = light->specularscale;
2649         rtlight->flags = light->flags;
2650         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2651         // ConcatScale won't work here because this needs to scale rotate and
2652         // translate, not just rotate
2653         scale = 1.0f / rtlight->radius;
2654         for (k = 0;k < 3;k++)
2655                 for (j = 0;j < 4;j++)
2656                         rtlight->matrix_worldtolight.m[k][j] *= scale;
2657         Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2658         Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2659
2660         rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2661         rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2662         VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2663         rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2664 }
2665
2666 // compiles rtlight geometry
2667 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2668 void R_RTLight_Compile(rtlight_t *rtlight)
2669 {
2670         int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2671         entity_render_t *ent = r_refdef.worldentity;
2672         model_t *model = r_refdef.worldmodel;
2673         qbyte *data;
2674
2675         // compile the light
2676         rtlight->compiled = true;
2677         rtlight->static_numleafs = 0;
2678         rtlight->static_numleafpvsbytes = 0;
2679         rtlight->static_leaflist = NULL;
2680         rtlight->static_leafpvs = NULL;
2681         rtlight->static_numsurfaces = 0;
2682         rtlight->static_surfacelist = NULL;
2683         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2684         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2685         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2686         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2687         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2688         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2689
2690         if (model && model->GetLightInfo)
2691         {
2692                 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2693                 r_shadow_compilingrtlight = rtlight;
2694                 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->brush.num_surfaces);
2695                 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);
2696                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2697                 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2698                 rtlight->static_numleafs = numleafs;
2699                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2700                 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2701                 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2702                 rtlight->static_numsurfaces = numsurfaces;
2703                 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2704                 if (numleafs)
2705                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2706                 if (numleafpvsbytes)
2707                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2708                 if (numsurfaces)
2709                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2710                 if (model->DrawShadowVolume && rtlight->shadow)
2711                 {
2712                         rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2713                         model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2714                         rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2715                 }
2716                 if (model->DrawLight)
2717                 {
2718                         rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2719                         model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, 0, 0, 0, numsurfaces, r_shadow_buffer_surfacelist, 0);
2720                         rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2721                 }
2722                 // switch back to rendering when DrawShadowVolume or DrawLight is called
2723                 r_shadow_compilingrtlight = NULL;
2724         }
2725
2726
2727         // use smallest available cullradius - box radius or light radius
2728         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2729         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2730
2731         shadowmeshes = 0;
2732         shadowtris = 0;
2733         if (rtlight->static_meshchain_shadow)
2734         {
2735                 shadowmesh_t *mesh;
2736                 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2737                 {
2738                         shadowmeshes++;
2739                         shadowtris += mesh->numtriangles;
2740                 }
2741         }
2742
2743         lightmeshes = 0;
2744         lighttris = 0;
2745         if (rtlight->static_meshchain_light)
2746         {
2747                 shadowmesh_t *mesh;
2748                 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2749                 {
2750                         lightmeshes++;
2751                         lighttris += mesh->numtriangles;
2752                 }
2753         }
2754
2755         Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes), %i light triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes, lighttris, lightmeshes);
2756 }
2757
2758 void R_RTLight_Uncompile(rtlight_t *rtlight)
2759 {
2760         if (rtlight->compiled)
2761         {
2762                 if (rtlight->static_meshchain_shadow)
2763                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2764                 rtlight->static_meshchain_shadow = NULL;
2765                 if (rtlight->static_meshchain_light)
2766                         Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2767                 rtlight->static_meshchain_light = NULL;
2768                 // these allocations are grouped
2769                 if (rtlight->static_leaflist)
2770                         Mem_Free(rtlight->static_leaflist);
2771                 rtlight->static_numleafs = 0;
2772                 rtlight->static_numleafpvsbytes = 0;
2773                 rtlight->static_leaflist = NULL;
2774                 rtlight->static_leafpvs = NULL;
2775                 rtlight->static_numsurfaces = 0;
2776                 rtlight->static_surfacelist = NULL;
2777                 rtlight->compiled = false;
2778         }
2779 }
2780
2781 void R_Shadow_UncompileWorldLights(void)
2782 {
2783         dlight_t *light;
2784         for (light = r_shadow_worldlightchain;light;light = light->next)
2785                 R_RTLight_Uncompile(&light->rtlight);
2786 }
2787
2788 void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
2789 {
2790         int i, shadow, usestencil;
2791         entity_render_t *ent;
2792         float f;
2793         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2794         rtexture_t *cubemaptexture;
2795         matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2796         int numleafs, numsurfaces;
2797         int *leaflist, *surfacelist;
2798         qbyte *leafpvs;
2799         vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2800         shadowmesh_t *mesh;
2801         rmeshstate_t m;
2802
2803         // skip lights that don't light (corona only lights)
2804         if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2805                 return;
2806
2807         f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2808         VectorScale(rtlight->color, f, lightcolor);
2809         if (VectorLength2(lightcolor) < 0.01)
2810                 return;
2811         /*
2812         if (rtlight->selected)
2813         {
2814                 f = 2 + sin(realtime * M_PI * 4.0);
2815                 VectorScale(lightcolor, f, lightcolor);
2816         }
2817         */
2818
2819         // loading is done before visibility checks because loading should happen
2820         // all at once at the start of a level, not when it stalls gameplay.
2821         // (especially important to benchmarks)
2822         if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2823                 R_RTLight_Compile(rtlight);
2824         if (rtlight->cubemapname[0])
2825                 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2826         else
2827                 cubemaptexture = NULL;
2828
2829         cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2830         cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2831         cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2832         cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2833         cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2834         cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2835         if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2836                 return;
2837         numleafs = 0;
2838         leaflist = NULL;
2839         leafpvs = NULL;
2840         numsurfaces = 0;
2841         surfacelist = NULL;
2842         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2843         {
2844                 // compiled light, world available and can receive realtime lighting
2845                 // retrieve leaf information
2846                 numleafs = rtlight->static_numleafs;
2847                 leaflist = rtlight->static_leaflist;
2848                 leafpvs = rtlight->static_leafpvs;
2849                 numsurfaces = rtlight->static_numsurfaces;
2850                 surfacelist = rtlight->static_surfacelist;
2851                 VectorCopy(rtlight->cullmins, cullmins);
2852                 VectorCopy(rtlight->cullmaxs, cullmaxs);
2853         }
2854         else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2855         {
2856                 // dynamic light, world available and can receive realtime lighting
2857                 // if the light box is offscreen, skip it right away
2858                 if (R_CullBox(cullmins, cullmaxs))
2859                         return;
2860                 // calculate lit surfaces and leafs
2861                 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
2862                 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2863                 leaflist = r_shadow_buffer_leaflist;
2864                 leafpvs = r_shadow_buffer_leafpvs;
2865                 surfacelist = r_shadow_buffer_surfacelist;
2866         }
2867         // if the reduced leaf bounds are offscreen, skip it
2868         if (R_CullBox(cullmins, cullmaxs))
2869                 return;
2870         // check if light is illuminating any visible leafs
2871         if (numleafs)
2872         {
2873                 for (i = 0;i < numleafs;i++)
2874                         if (r_worldleafvisible[leaflist[i]])
2875                                 break;
2876                 if (i == numleafs)
2877                         return;
2878         }
2879         // set up a scissor rectangle for this light
2880         if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2881                 return;
2882
2883         shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2884         usestencil = false;
2885
2886         if (shadow && ((gl_stencil && !visiblelighting) || visiblevolumes))
2887         {
2888                 if (visiblevolumes)
2889                 {
2890                        &