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