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