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