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