reduced client memory usage by 29MB by making cl_max_entities dynamic (starts out...
[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_distance", "1024"};
197 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
198 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
199 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "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_EnlargeClusterBuffer(int numclusters)
674 {
675         int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
676         if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
677         {
678                 if (r_shadow_buffer_clusterpvs)
679                         Mem_Free(r_shadow_buffer_clusterpvs);
680                 if (r_shadow_buffer_clusterlist)
681                         Mem_Free(r_shadow_buffer_clusterlist);
682                 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
683                 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
684                 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
685         }
686 }
687
688 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
689 {
690         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
691         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
692         {
693                 if (r_shadow_buffer_surfacepvs)
694                         Mem_Free(r_shadow_buffer_surfacepvs);
695                 if (r_shadow_buffer_surfacelist)
696                         Mem_Free(r_shadow_buffer_surfacelist);
697                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
698                 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
699                 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
700         }
701 }
702
703 void R_Shadow_PrepareShadowMark(int numtris)
704 {
705         // make sure shadowmark is big enough for this volume
706         if (maxshadowmark < numtris)
707         {
708                 maxshadowmark = numtris;
709                 if (shadowmark)
710                         Mem_Free(shadowmark);
711                 if (shadowmarklist)
712                         Mem_Free(shadowmarklist);
713                 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
714                 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
715                 shadowmarkcount = 0;
716         }
717         shadowmarkcount++;
718         // if shadowmarkcount wrapped we clear the array and adjust accordingly
719         if (shadowmarkcount == 0)
720         {
721                 shadowmarkcount = 1;
722                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
723         }
724         numshadowmark = 0;
725 }
726
727 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)
728 {
729         int i, j;
730         int outtriangles = 0, outvertices = 0;
731         const int *element;
732         const float *vertex;
733
734         if (maxvertexupdate < innumvertices)
735         {
736                 maxvertexupdate = innumvertices;
737                 if (vertexupdate)
738                         Mem_Free(vertexupdate);
739                 if (vertexremap)
740                         Mem_Free(vertexremap);
741                 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
742                 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
743                 vertexupdatenum = 0;
744         }
745         vertexupdatenum++;
746         if (vertexupdatenum == 0)
747         {
748                 vertexupdatenum = 1;
749                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
750                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
751         }
752
753         for (i = 0;i < numshadowmarktris;i++)
754                 shadowmark[shadowmarktris[i]] = shadowmarkcount;
755
756         for (i = 0;i < numshadowmarktris;i++)
757         {
758                 element = inelement3i + shadowmarktris[i] * 3;
759                 // make sure the vertices are created
760                 for (j = 0;j < 3;j++)
761                 {
762                         if (vertexupdate[element[j]] != vertexupdatenum)
763                         {
764                                 float ratio, direction[3];
765                                 vertexupdate[element[j]] = vertexupdatenum;
766                                 vertexremap[element[j]] = outvertices;
767                                 vertex = invertex3f + element[j] * 3;
768                                 // project one copy of the vertex to the sphere radius of the light
769                                 // (FIXME: would projecting it to the light box be better?)
770                                 VectorSubtract(vertex, projectorigin, direction);
771                                 ratio = projectdistance / VectorLength(direction);
772                                 VectorCopy(vertex, outvertex3f);
773                                 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
774                                 outvertex3f += 6;
775                                 outvertices += 2;
776                         }
777                 }
778         }
779
780         for (i = 0;i < numshadowmarktris;i++)
781         {
782                 int remappedelement[3];
783                 int markindex;
784                 const int *neighbortriangle;
785
786                 markindex = shadowmarktris[i] * 3;
787                 element = inelement3i + markindex;
788                 neighbortriangle = inneighbor3i + markindex;
789                 // output the front and back triangles
790                 outelement3i[0] = vertexremap[element[0]];
791                 outelement3i[1] = vertexremap[element[1]];
792                 outelement3i[2] = vertexremap[element[2]];
793                 outelement3i[3] = vertexremap[element[2]] + 1;
794                 outelement3i[4] = vertexremap[element[1]] + 1;
795                 outelement3i[5] = vertexremap[element[0]] + 1;
796
797                 outelement3i += 6;
798                 outtriangles += 2;
799                 // output the sides (facing outward from this triangle)
800                 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
801                 {
802                         remappedelement[0] = vertexremap[element[0]];
803                         remappedelement[1] = vertexremap[element[1]];
804                         outelement3i[0] = remappedelement[1];
805                         outelement3i[1] = remappedelement[0];
806                         outelement3i[2] = remappedelement[0] + 1;
807                         outelement3i[3] = remappedelement[1];
808                         outelement3i[4] = remappedelement[0] + 1;
809                         outelement3i[5] = remappedelement[1] + 1;
810
811                         outelement3i += 6;
812                         outtriangles += 2;
813                 }
814                 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
815                 {
816                         remappedelement[1] = vertexremap[element[1]];
817                         remappedelement[2] = vertexremap[element[2]];
818                         outelement3i[0] = remappedelement[2];
819                         outelement3i[1] = remappedelement[1];
820                         outelement3i[2] = remappedelement[1] + 1;
821                         outelement3i[3] = remappedelement[2];
822                         outelement3i[4] = remappedelement[1] + 1;
823                         outelement3i[5] = remappedelement[2] + 1;
824
825                         outelement3i += 6;
826                         outtriangles += 2;
827                 }
828                 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
829                 {
830                         remappedelement[0] = vertexremap[element[0]];
831                         remappedelement[2] = vertexremap[element[2]];
832                         outelement3i[0] = remappedelement[0];
833                         outelement3i[1] = remappedelement[2];
834                         outelement3i[2] = remappedelement[2] + 1;
835                         outelement3i[3] = remappedelement[0];
836                         outelement3i[4] = remappedelement[2] + 1;
837                         outelement3i[5] = remappedelement[0] + 1;
838
839                         outelement3i += 6;
840                         outtriangles += 2;
841                 }
842         }
843         if (outnumvertices)
844                 *outnumvertices = outvertices;
845         return outtriangles;
846 }
847
848 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)
849 {
850         int tris, outverts;
851         if (projectdistance < 0.1)
852         {
853                 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
854                 return;
855         }
856         if (!numverts || !nummarktris)
857                 return;
858         // make sure shadowelements is big enough for this volume
859         if (maxshadowelements < nummarktris * 24)
860                 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
861         tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
862         R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
863 }
864
865 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)
866 {
867         int t, tend;
868         const int *e;
869         const float *v[3];
870         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
871                 return;
872         tend = firsttriangle + numtris;
873         if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
874          && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
875          && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
876         {
877                 // surface box entirely inside light box, no box cull
878                 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
879                         if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
880                                 shadowmarklist[numshadowmark++] = t;
881         }
882         else
883         {
884                 // surface box not entirely inside light box, cull each triangle
885                 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
886                 {
887                         v[0] = invertex3f + e[0] * 3;
888                         v[1] = invertex3f + e[1] * 3;
889                         v[2] = invertex3f + e[2] * 3;
890                         if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
891                          && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
892                          && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
893                          && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
894                          && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
895                          && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
896                          && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
897                                 shadowmarklist[numshadowmark++] = t;
898                 }
899         }
900 }
901
902 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
903 {
904         rmeshstate_t m;
905         if (r_shadow_compilingrtlight)
906         {
907                 // if we're compiling an rtlight, capture the mesh
908                 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
909                 return;
910         }
911         memset(&m, 0, sizeof(m));
912         m.pointer_vertex = vertex3f;
913         R_Mesh_State(&m);
914         GL_LockArrays(0, numvertices);
915         if (r_shadowstage == SHADOWSTAGE_STENCIL)
916         {
917                 // increment stencil if backface is behind depthbuffer
918                 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
919                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
920                 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
921                 c_rt_shadowmeshes++;
922                 c_rt_shadowtris += numtriangles;
923                 // decrement stencil if frontface is behind depthbuffer
924                 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
925                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
926         }
927         R_Mesh_Draw(0, numvertices, numtriangles, element3i);
928         c_rt_shadowmeshes++;
929         c_rt_shadowtris += numtriangles;
930         GL_LockArrays(0, 0);
931 }
932
933 static void R_Shadow_MakeTextures(void)
934 {
935         int x, y, z, d, side;
936         float v[3], s, t, intensity;
937         qbyte *data;
938         R_FreeTexturePool(&r_shadow_texturepool);
939         r_shadow_texturepool = R_AllocTexturePool();
940         r_shadow_attenpower = r_shadow_lightattenuationpower.value;
941         r_shadow_attenscale = r_shadow_lightattenuationscale.value;
942 #define NORMSIZE 64
943 #define ATTEN2DSIZE 64
944 #define ATTEN3DSIZE 32
945         data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
946         r_shadow_blankwhitecubetexture = NULL;
947         r_shadow_normalcubetexture = NULL;
948         if (gl_texturecubemap)
949         {
950                 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
951                 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
952                 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
953                 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
954                 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
955                 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
956                 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
957                 for (side = 0;side < 6;side++)
958                 {
959                         for (y = 0;y < NORMSIZE;y++)
960                         {
961                                 for (x = 0;x < NORMSIZE;x++)
962                                 {
963                                         s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
964                                         t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
965                                         switch(side)
966                                         {
967                                         case 0:
968                                                 v[0] = 1;
969                                                 v[1] = -t;
970                                                 v[2] = -s;
971                                                 break;
972                                         case 1:
973                                                 v[0] = -1;
974                                                 v[1] = -t;
975                                                 v[2] = s;
976                                                 break;
977                                         case 2:
978                                                 v[0] = s;
979                                                 v[1] = 1;
980                                                 v[2] = t;
981                                                 break;
982                                         case 3:
983                                                 v[0] = s;
984                                                 v[1] = -1;
985                                                 v[2] = -t;
986                                                 break;
987                                         case 4:
988                                                 v[0] = s;
989                                                 v[1] = -t;
990                                                 v[2] = 1;
991                                                 break;
992                                         case 5:
993                                                 v[0] = -s;
994                                                 v[1] = -t;
995                                                 v[2] = -1;
996                                                 break;
997                                         }
998                                         intensity = 127.0f / sqrt(DotProduct(v, v));
999                                         data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1000                                         data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1001                                         data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1002                                         data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1003                                 }
1004                         }
1005                 }
1006                 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1007         }
1008         for (y = 0;y < ATTEN2DSIZE;y++)
1009         {
1010                 for (x = 0;x < ATTEN2DSIZE;x++)
1011                 {
1012                         v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1013                         v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1014                         v[2] = 0;
1015                         intensity = 1.0f - sqrt(DotProduct(v, v));
1016                         if (intensity > 0)
1017                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1018                         d = bound(0, intensity, 255);
1019                         data[(y*ATTEN2DSIZE+x)*4+0] = d;
1020                         data[(y*ATTEN2DSIZE+x)*4+1] = d;
1021                         data[(y*ATTEN2DSIZE+x)*4+2] = d;
1022                         data[(y*ATTEN2DSIZE+x)*4+3] = d;
1023                 }
1024         }
1025         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1026         if (r_shadow_texture3d.integer)
1027         {
1028                 for (z = 0;z < ATTEN3DSIZE;z++)
1029                 {
1030                         for (y = 0;y < ATTEN3DSIZE;y++)
1031                         {
1032                                 for (x = 0;x < ATTEN3DSIZE;x++)
1033                                 {
1034                                         v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1035                                         v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1036                                         v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1037                                         intensity = 1.0f - sqrt(DotProduct(v, v));
1038                                         if (intensity > 0)
1039                                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1040                                         d = bound(0, intensity, 255);
1041                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1042                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1043                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1044                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1045                                 }
1046                         }
1047                 }
1048                 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1049         }
1050         Mem_Free(data);
1051 }
1052
1053 void R_Shadow_ValidateCvars(void)
1054 {
1055         if (r_shadow_texture3d.integer && !gl_texture3d)
1056                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1057         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1058                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1059 }
1060
1061 void R_Shadow_Stage_Begin(void)
1062 {
1063         rmeshstate_t m;
1064
1065         R_Shadow_ValidateCvars();
1066
1067         if (!r_shadow_attenuation2dtexture
1068          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1069          || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1070          || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1071                 R_Shadow_MakeTextures();
1072
1073         memset(&m, 0, sizeof(m));
1074         GL_BlendFunc(GL_ONE, GL_ZERO);
1075         GL_DepthMask(false);
1076         GL_DepthTest(true);
1077         R_Mesh_State(&m);
1078         GL_Color(0, 0, 0, 1);
1079         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1080         qglEnable(GL_CULL_FACE);
1081         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1082         r_shadowstage = SHADOWSTAGE_NONE;
1083 }
1084
1085 void R_Shadow_Stage_ShadowVolumes(void)
1086 {
1087         rmeshstate_t m;
1088         memset(&m, 0, sizeof(m));
1089         R_Mesh_State(&m);
1090         GL_Color(1, 1, 1, 1);
1091         GL_ColorMask(0, 0, 0, 0);
1092         GL_BlendFunc(GL_ONE, GL_ZERO);
1093         GL_DepthMask(false);
1094         GL_DepthTest(true);
1095         qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1096         //if (r_shadow_shadow_polygonoffset.value != 0)
1097         //{
1098         //      qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1099         //      qglEnable(GL_POLYGON_OFFSET_FILL);
1100         //}
1101         //else
1102         //      qglDisable(GL_POLYGON_OFFSET_FILL);
1103         qglDepthFunc(GL_LESS);
1104         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1105         qglEnable(GL_STENCIL_TEST);
1106         qglStencilFunc(GL_ALWAYS, 128, ~0);
1107         if (gl_ext_stenciltwoside.integer)
1108         {
1109                 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1110                 qglDisable(GL_CULL_FACE);
1111                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1112                 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1113                 qglStencilMask(~0);
1114                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1115                 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1116                 qglStencilMask(~0);
1117                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1118         }
1119         else
1120         {
1121                 r_shadowstage = SHADOWSTAGE_STENCIL;
1122                 qglEnable(GL_CULL_FACE);
1123                 qglStencilMask(~0);
1124                 // this is changed by every shadow render so its value here is unimportant
1125                 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1126         }
1127         GL_Clear(GL_STENCIL_BUFFER_BIT);
1128         c_rt_clears++;
1129         // LordHavoc note: many shadow volumes reside entirely inside the world
1130         // (that is to say they are entirely bounded by their lit surfaces),
1131         // which can be optimized by handling things as an inverted light volume,
1132         // with the shadow boundaries of the world being simulated by an altered
1133         // (129) bias to stencil clearing on such lights
1134         // FIXME: generate inverted light volumes for use as shadow volumes and
1135         // optimize for them as noted above
1136 }
1137
1138 void R_Shadow_Stage_Light(int shadowtest)
1139 {
1140         rmeshstate_t m;
1141         memset(&m, 0, sizeof(m));
1142         R_Mesh_State(&m);
1143         GL_BlendFunc(GL_ONE, GL_ONE);
1144         GL_DepthMask(false);
1145         GL_DepthTest(true);
1146         qglPolygonOffset(0, 0);
1147         //qglDisable(GL_POLYGON_OFFSET_FILL);
1148         GL_Color(1, 1, 1, 1);
1149         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1150         qglDepthFunc(GL_EQUAL);
1151         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1152         qglEnable(GL_CULL_FACE);
1153         if (shadowtest)
1154                 qglEnable(GL_STENCIL_TEST);
1155         else
1156                 qglDisable(GL_STENCIL_TEST);
1157         if (gl_support_stenciltwoside)
1158                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1159         qglStencilMask(~0);
1160         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1161         // only draw light where this geometry was already rendered AND the
1162         // stencil is 128 (values other than this mean shadow)
1163         qglStencilFunc(GL_EQUAL, 128, ~0);
1164         r_shadowstage = SHADOWSTAGE_LIGHT;
1165         c_rt_lights++;
1166 }
1167
1168 void R_Shadow_Stage_End(void)
1169 {
1170         rmeshstate_t m;
1171         memset(&m, 0, sizeof(m));
1172         R_Mesh_State(&m);
1173         GL_BlendFunc(GL_ONE, GL_ZERO);
1174         GL_DepthMask(true);
1175         GL_DepthTest(true);
1176         qglPolygonOffset(0, 0);
1177         //qglDisable(GL_POLYGON_OFFSET_FILL);
1178         GL_Color(1, 1, 1, 1);
1179         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1180         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1181         qglDepthFunc(GL_LEQUAL);
1182         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1183         qglDisable(GL_STENCIL_TEST);
1184         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1185         if (gl_support_stenciltwoside)
1186                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1187         qglStencilMask(~0);
1188         qglStencilFunc(GL_ALWAYS, 128, ~0);
1189         r_shadowstage = SHADOWSTAGE_NONE;
1190 }
1191
1192 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1193 {
1194         int i, ix1, iy1, ix2, iy2;
1195         float x1, y1, x2, y2, x, y, f;
1196         vec3_t smins, smaxs;
1197         vec4_t v, v2;
1198         if (!r_shadow_scissor.integer)
1199                 return false;
1200         // if view is inside the box, just say yes it's visible
1201         if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1202         {
1203                 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1204                 return false;
1205         }
1206         for (i = 0;i < 3;i++)
1207         {
1208                 if (r_viewforward[i] >= 0)
1209                 {
1210                         v[i] = mins[i];
1211                         v2[i] = maxs[i];
1212                 }
1213                 else
1214                 {
1215                         v[i] = maxs[i];
1216                         v2[i] = mins[i];
1217                 }
1218         }
1219         f = DotProduct(r_viewforward, r_vieworigin) + 1;
1220         if (DotProduct(r_viewforward, v2) <= f)
1221         {
1222                 // entirely behind nearclip plane
1223                 return true;
1224         }
1225         if (DotProduct(r_viewforward, v) >= f)
1226         {
1227                 // entirely infront of nearclip plane
1228                 x1 = y1 = x2 = y2 = 0;
1229                 for (i = 0;i < 8;i++)
1230                 {
1231                         v[0] = (i & 1) ? mins[0] : maxs[0];
1232                         v[1] = (i & 2) ? mins[1] : maxs[1];
1233                         v[2] = (i & 4) ? mins[2] : maxs[2];
1234                         v[3] = 1.0f;
1235                         GL_TransformToScreen(v, v2);
1236                         //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]);
1237                         x = v2[0];
1238                         y = v2[1];
1239                         if (i)
1240                         {
1241                                 if (x1 > x) x1 = x;
1242                                 if (x2 < x) x2 = x;
1243                                 if (y1 > y) y1 = y;
1244                                 if (y2 < y) y2 = y;
1245                         }
1246                         else
1247                         {
1248                                 x1 = x2 = x;
1249                                 y1 = y2 = y;
1250                         }
1251                 }
1252         }
1253         else
1254         {
1255                 // clipped by nearclip plane
1256                 // this is nasty and crude...
1257                 // create viewspace bbox
1258                 for (i = 0;i < 8;i++)
1259                 {
1260                         v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1261                         v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1262                         v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1263                         v2[0] = -DotProduct(v, r_viewleft);
1264                         v2[1] = DotProduct(v, r_viewup);
1265                         v2[2] = DotProduct(v, r_viewforward);
1266                         if (i)
1267                         {
1268                                 if (smins[0] > v2[0]) smins[0] = v2[0];
1269                                 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1270                                 if (smins[1] > v2[1]) smins[1] = v2[1];
1271                                 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1272                                 if (smins[2] > v2[2]) smins[2] = v2[2];
1273                                 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1274                         }
1275                         else
1276                         {
1277                                 smins[0] = smaxs[0] = v2[0];
1278                                 smins[1] = smaxs[1] = v2[1];
1279                                 smins[2] = smaxs[2] = v2[2];
1280                         }
1281                 }
1282                 // now we have a bbox in viewspace
1283                 // clip it to the view plane
1284                 if (smins[2] < 1)
1285                         smins[2] = 1;
1286                 // return true if that culled the box
1287                 if (smins[2] >= smaxs[2])
1288                         return true;
1289                 // ok some of it is infront of the view, transform each corner back to
1290                 // worldspace and then to screenspace and make screen rect
1291                 // initialize these variables just to avoid compiler warnings
1292                 x1 = y1 = x2 = y2 = 0;
1293                 for (i = 0;i < 8;i++)
1294                 {
1295                         v2[0] = (i & 1) ? smins[0] : smaxs[0];
1296                         v2[1] = (i & 2) ? smins[1] : smaxs[1];
1297                         v2[2] = (i & 4) ? smins[2] : smaxs[2];
1298                         v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1299                         v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1300                         v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1301                         v[3] = 1.0f;
1302                         GL_TransformToScreen(v, v2);
1303                         //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]);
1304                         x = v2[0];
1305                         y = v2[1];
1306                         if (i)
1307                         {
1308                                 if (x1 > x) x1 = x;
1309                                 if (x2 < x) x2 = x;
1310                                 if (y1 > y) y1 = y;
1311                                 if (y2 < y) y2 = y;
1312                         }
1313                         else
1314                         {
1315                                 x1 = x2 = x;
1316                                 y1 = y2 = y;
1317                         }
1318                 }
1319                 /*
1320                 // this code doesn't handle boxes with any points behind view properly
1321                 x1 = 1000;x2 = -1000;
1322                 y1 = 1000;y2 = -1000;
1323                 for (i = 0;i < 8;i++)
1324                 {
1325                         v[0] = (i & 1) ? mins[0] : maxs[0];
1326                         v[1] = (i & 2) ? mins[1] : maxs[1];
1327                         v[2] = (i & 4) ? mins[2] : maxs[2];
1328                         v[3] = 1.0f;
1329                         GL_TransformToScreen(v, v2);
1330                         //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]);
1331                         if (v2[2] > 0)
1332                         {
1333                                 x = v2[0];
1334                                 y = v2[1];
1335
1336                                 if (x1 > x) x1 = x;
1337                                 if (x2 < x) x2 = x;
1338                                 if (y1 > y) y1 = y;
1339                                 if (y2 < y) y2 = y;
1340                         }
1341                 }
1342                 */
1343         }
1344         ix1 = x1 - 1.0f;
1345         iy1 = y1 - 1.0f;
1346         ix2 = x2 + 1.0f;
1347         iy2 = y2 + 1.0f;
1348         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1349         if (ix1 < r_view_x) ix1 = r_view_x;
1350         if (iy1 < r_view_y) iy1 = r_view_y;
1351         if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1352         if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1353         if (ix2 <= ix1 || iy2 <= iy1)
1354                 return true;
1355         // set up the scissor rectangle
1356         GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1357         //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1358         //qglEnable(GL_SCISSOR_TEST);
1359         c_rt_scissored++;
1360         return false;
1361 }
1362
1363 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1364 {
1365         float *color4f = varray_color4f;
1366         float dist, dot, intensity, v[3], n[3];
1367         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1368         {
1369                 Matrix4x4_Transform(m, vertex3f, v);
1370                 if ((dist = DotProduct(v, v)) < 1)
1371                 {
1372                         Matrix4x4_Transform3x3(m, normal3f, n);
1373                         if ((dot = DotProduct(n, v)) > 0)
1374                         {
1375                                 dist = sqrt(dist);
1376                                 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1377                                 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1378                                 VectorScale(lightcolor, intensity, color4f);
1379                                 color4f[3] = 1;
1380                         }
1381                         else
1382                         {
1383                                 VectorClear(color4f);
1384                                 color4f[3] = 1;
1385                         }
1386                 }
1387                 else
1388                 {
1389                         VectorClear(color4f);
1390                         color4f[3] = 1;
1391                 }
1392         }
1393 }
1394
1395 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1396 {
1397         float *color4f = varray_color4f;
1398         float dist, dot, intensity, v[3], n[3];
1399         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1400         {
1401                 Matrix4x4_Transform(m, vertex3f, v);
1402                 if ((dist = fabs(v[2])) < 1)
1403                 {
1404                         Matrix4x4_Transform3x3(m, normal3f, n);
1405                         if ((dot = DotProduct(n, v)) > 0)
1406                         {
1407                                 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1408                                 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1409                                 VectorScale(lightcolor, intensity, color4f);
1410                                 color4f[3] = 1;
1411                         }
1412                         else
1413                         {
1414                                 VectorClear(color4f);
1415                                 color4f[3] = 1;
1416                         }
1417                 }
1418                 else
1419                 {
1420                         VectorClear(color4f);
1421                         color4f[3] = 1;
1422                 }
1423         }
1424 }
1425
1426 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1427 {
1428         float *color4f = varray_color4f;
1429         float dot, intensity, v[3], n[3];
1430         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1431         {
1432                 Matrix4x4_Transform(m, vertex3f, v);
1433                 Matrix4x4_Transform3x3(m, normal3f, n);
1434                 if ((dot = DotProduct(n, v)) > 0)
1435                 {
1436                         intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1437                         VectorScale(lightcolor, intensity, color4f);
1438                         color4f[3] = 1;
1439                 }
1440                 else
1441                 {
1442                         VectorClear(color4f);
1443                         color4f[3] = 1;
1444                 }
1445         }
1446 }
1447
1448 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1449 {
1450         float *color4f = varray_color4f;
1451         float dist, intensity, v[3];
1452         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1453         {
1454                 Matrix4x4_Transform(m, vertex3f, v);
1455                 if ((dist = DotProduct(v, v)) < 1)
1456                 {
1457                         dist = sqrt(dist);
1458                         intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1459                         VectorScale(lightcolor, intensity, color4f);
1460                         color4f[3] = 1;
1461                 }
1462                 else
1463                 {
1464                         VectorClear(color4f);
1465                         color4f[3] = 1;
1466                 }
1467         }
1468 }
1469
1470 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1471 {
1472         float *color4f = varray_color4f;
1473         float dist, intensity, v[3];
1474         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1475         {
1476                 Matrix4x4_Transform(m, vertex3f, v);
1477                 if ((dist = fabs(v[2])) < 1)
1478                 {
1479                         intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1480                         VectorScale(lightcolor, intensity, color4f);
1481                         color4f[3] = 1;
1482                 }
1483                 else
1484                 {
1485                         VectorClear(color4f);
1486                         color4f[3] = 1;
1487                 }
1488         }
1489 }
1490
1491 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1492 #define USETEXMATRIX
1493
1494 #ifndef USETEXMATRIX
1495 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1496 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1497 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1498 {
1499         do
1500         {
1501                 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1502                 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1503                 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1504                 vertex3f += 3;
1505                 tc3f += 3;
1506         }
1507         while (--numverts);
1508 }
1509
1510 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1511 {
1512         do
1513         {
1514                 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1515                 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1516                 vertex3f += 3;
1517                 tc2f += 2;
1518         }
1519         while (--numverts);
1520 }
1521 #endif
1522
1523 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)
1524 {
1525         int i;
1526         float lightdir[3];
1527         for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1528         {
1529                 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1530                 // the cubemap normalizes this for us
1531                 out3f[0] = DotProduct(svector3f, lightdir);
1532                 out3f[1] = DotProduct(tvector3f, lightdir);
1533                 out3f[2] = DotProduct(normal3f, lightdir);
1534         }
1535 }
1536
1537 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)
1538 {
1539         int i;
1540         float lightdir[3], eyedir[3], halfdir[3];
1541         for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1542         {
1543                 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1544                 VectorNormalizeFast(lightdir);
1545                 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1546                 VectorNormalizeFast(eyedir);
1547                 VectorAdd(lightdir, eyedir, halfdir);
1548                 // the cubemap normalizes this for us
1549                 out3f[0] = DotProduct(svector3f, halfdir);
1550                 out3f[1] = DotProduct(tvector3f, halfdir);
1551                 out3f[2] = DotProduct(normal3f, halfdir);
1552         }
1553 }
1554
1555 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 *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
1556 {
1557         int renders;
1558         float color[3], color2[3], colorscale;
1559         rmeshstate_t m;
1560         // FIXME: support EF_NODEPTHTEST
1561         GL_DepthMask(false);
1562         GL_DepthTest(true);
1563         if (!bumptexture)
1564                 bumptexture = r_texture_blanknormalmap;
1565         specularscale *= r_shadow_glossintensity.value;
1566         if (!glosstexture)
1567         {
1568                 if (r_shadow_gloss.integer >= 2)
1569                 {
1570                         glosstexture = r_texture_white;
1571                         specularscale *= r_shadow_gloss2intensity.value;
1572                 }
1573                 else
1574                 {
1575                         glosstexture = r_texture_black;
1576                         specularscale = 0;
1577                 }
1578         }
1579         if (r_shadow_gloss.integer < 1)
1580                 specularscale = 0;
1581         if (!lightcubemap)
1582                 lightcubemap = r_shadow_blankwhitecubetexture;
1583         if (ambientscale + diffusescale + specularscale < 0.01)
1584                 return;
1585         if (r_shadow_glsl.integer && r_shadow_program_light[0])
1586         {
1587                 unsigned int perm, prog;
1588                 // GLSL shader path (GFFX5200, Radeon 9500)
1589                 memset(&m, 0, sizeof(m));
1590                 m.pointer_vertex = vertex3f;
1591                 m.pointer_texcoord[0] = texcoord2f;
1592                 m.pointer_texcoord3f[1] = svector3f;
1593                 m.pointer_texcoord3f[2] = tvector3f;
1594                 m.pointer_texcoord3f[3] = normal3f;
1595                 m.tex[0] = R_GetTexture(bumptexture);
1596                 m.tex[1] = R_GetTexture(basetexture);
1597                 m.tex[2] = R_GetTexture(glosstexture);
1598                 m.texcubemap[3] = R_GetTexture(lightcubemap);
1599                 // TODO: support fog (after renderer is converted to texture fog)
1600                 m.tex[4] = R_GetTexture(r_texture_white);
1601                 m.texmatrix[3] = *matrix_modeltolight;
1602                 R_Mesh_State(&m);
1603                 GL_BlendFunc(GL_ONE, GL_ONE);
1604                 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1605                 CHECKGLERROR
1606                 perm = 0;
1607                 // only add a feature to the permutation if that permutation exists
1608                 // (otherwise it might end up not using a shader at all, which looks
1609                 // worse than using less features)
1610                 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1611                         perm |= SHADERPERMUTATION_SPECULAR;
1612                 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1613                 //      perm |= SHADERPERMUTATION_FOG;
1614                 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1615                         perm |= SHADERPERMUTATION_CUBEFILTER;
1616                 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1617                         perm |= SHADERPERMUTATION_OFFSETMAPPING;
1618                 prog = r_shadow_program_light[perm];
1619                 qglUseProgramObjectARB(prog);CHECKGLERROR
1620                 // TODO: support fog (after renderer is converted to texture fog)
1621                 if (perm & SHADERPERMUTATION_FOG)
1622                 {
1623                         qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1624                 }
1625                 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1626                 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1627                 if (perm & SHADERPERMUTATION_SPECULAR)
1628                 {
1629                         qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1630                         qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1631                 }
1632                 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);CHECKGLERROR
1633                 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1634                 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1635                 {
1636                         qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1637                 }
1638                 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1639                 {
1640                         qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1641                         qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1642                 }
1643                 CHECKGLERROR
1644                 GL_LockArrays(firstvertex, numvertices);
1645                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1646                 c_rt_lightmeshes++;
1647                 c_rt_lighttris += numtriangles;
1648                 GL_LockArrays(0, 0);
1649                 qglUseProgramObjectARB(0);
1650                 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1651                 qglBegin(GL_TRIANGLES);
1652                 qglEnd();
1653                 CHECKGLERROR
1654         }
1655         else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1656         {
1657                 if (!bumptexture)
1658                         bumptexture = r_texture_blanknormalmap;
1659                 if (!glosstexture)
1660                         glosstexture = r_texture_white;
1661                 if (ambientscale)
1662                 {
1663                         GL_Color(1,1,1,1);
1664                         colorscale = ambientscale;
1665                         // colorscale accounts for how much we multiply the brightness
1666                         // during combine.
1667                         //
1668                         // mult is how many times the final pass of the lighting will be
1669                         // performed to get more brightness than otherwise possible.
1670                         //
1671                         // Limit mult to 64 for sanity sake.
1672                         if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1673                         {
1674                                 // 3 3D combine path (Geforce3, Radeon 8500)
1675                                 memset(&m, 0, sizeof(m));
1676                                 m.pointer_vertex = vertex3f;
1677                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1678 #ifdef USETEXMATRIX
1679                                 m.pointer_texcoord3f[0] = vertex3f;
1680                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1681 #else
1682                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1683                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1684 #endif
1685                                 m.tex[1] = R_GetTexture(basetexture);
1686                                 m.pointer_texcoord[1] = texcoord2f;
1687                                 m.texcubemap[2] = R_GetTexture(lightcubemap);
1688 #ifdef USETEXMATRIX
1689                                 m.pointer_texcoord3f[2] = vertex3f;
1690                                 m.texmatrix[2] = *matrix_modeltolight;
1691 #else
1692                                 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1693                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1694 #endif
1695                                 GL_BlendFunc(GL_ONE, GL_ONE);
1696                         }
1697                         else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1698                         {
1699                                 // 2 3D combine path (Geforce3, original Radeon)
1700                                 memset(&m, 0, sizeof(m));
1701                                 m.pointer_vertex = vertex3f;
1702                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1703 #ifdef USETEXMATRIX
1704                                 m.pointer_texcoord3f[0] = vertex3f;
1705                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1706 #else
1707                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1708                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1709 #endif
1710                                 m.tex[1] = R_GetTexture(basetexture);
1711                                 m.pointer_texcoord[1] = texcoord2f;
1712                                 GL_BlendFunc(GL_ONE, GL_ONE);
1713                         }
1714                         else if (r_textureunits.integer >= 4 && lightcubemap)
1715                         {
1716                                 // 4 2D combine path (Geforce3, Radeon 8500)
1717                                 memset(&m, 0, sizeof(m));
1718                                 m.pointer_vertex = vertex3f;
1719                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1720 #ifdef USETEXMATRIX
1721                                 m.pointer_texcoord3f[0] = vertex3f;
1722                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1723 #else
1724                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1725                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1726 #endif
1727                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1728 #ifdef USETEXMATRIX
1729                                 m.pointer_texcoord3f[1] = vertex3f;
1730                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1731 #else
1732                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1733                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1734 #endif
1735                                 m.tex[2] = R_GetTexture(basetexture);
1736                                 m.pointer_texcoord[2] = texcoord2f;
1737                                 if (lightcubemap)
1738                                 {
1739                                         m.texcubemap[3] = R_GetTexture(lightcubemap);
1740 #ifdef USETEXMATRIX
1741                                         m.pointer_texcoord3f[3] = vertex3f;
1742                                         m.texmatrix[3] = *matrix_modeltolight;
1743 #else
1744                                         m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1745                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1746 #endif
1747                                 }
1748                                 GL_BlendFunc(GL_ONE, GL_ONE);
1749                         }
1750                         else if (r_textureunits.integer >= 3 && !lightcubemap)
1751                         {
1752                                 // 3 2D combine path (Geforce3, original Radeon)
1753                                 memset(&m, 0, sizeof(m));
1754                                 m.pointer_vertex = vertex3f;
1755                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1756 #ifdef USETEXMATRIX
1757                                 m.pointer_texcoord3f[0] = vertex3f;
1758                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1759 #else
1760                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1761                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1762 #endif
1763                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1764 #ifdef USETEXMATRIX
1765                                 m.pointer_texcoord3f[1] = vertex3f;
1766                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1767 #else
1768                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1769                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1770 #endif
1771                                 m.tex[2] = R_GetTexture(basetexture);
1772                                 m.pointer_texcoord[2] = texcoord2f;
1773                                 GL_BlendFunc(GL_ONE, GL_ONE);
1774                         }
1775                         else
1776                         {
1777                                 // 2/2/2 2D combine path (any dot3 card)
1778                                 memset(&m, 0, sizeof(m));
1779                                 m.pointer_vertex = vertex3f;
1780                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1781 #ifdef USETEXMATRIX
1782                                 m.pointer_texcoord3f[0] = vertex3f;
1783                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1784 #else
1785                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1786                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1787 #endif
1788                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1789 #ifdef USETEXMATRIX
1790                                 m.pointer_texcoord3f[1] = vertex3f;
1791                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1792 #else
1793                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1794                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1795 #endif
1796                                 R_Mesh_State(&m);
1797                                 GL_ColorMask(0,0,0,1);
1798                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1799                                 GL_LockArrays(firstvertex, numvertices);
1800                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1801                                 GL_LockArrays(0, 0);
1802                                 c_rt_lightmeshes++;
1803                                 c_rt_lighttris += numtriangles;
1804
1805                                 memset(&m, 0, sizeof(m));
1806                                 m.pointer_vertex = vertex3f;
1807                                 m.tex[0] = R_GetTexture(basetexture);
1808                                 m.pointer_texcoord[0] = texcoord2f;
1809                                 if (lightcubemap)
1810                                 {
1811                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1812 #ifdef USETEXMATRIX
1813                                         m.pointer_texcoord3f[1] = vertex3f;
1814                                         m.texmatrix[1] = *matrix_modeltolight;
1815 #else
1816                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1817                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1818 #endif
1819                                 }
1820                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1821                         }
1822                         // this final code is shared
1823                         R_Mesh_State(&m);
1824                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1825                         VectorScale(lightcolor, colorscale, color2);
1826                         GL_LockArrays(firstvertex, numvertices);
1827                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1828                         {
1829                                 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1830                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1831                                 c_rt_lightmeshes++;
1832                                 c_rt_lighttris += numtriangles;
1833                         }
1834                         GL_LockArrays(0, 0);
1835                 }
1836                 if (diffusescale)
1837                 {
1838                         GL_Color(1,1,1,1);
1839                         colorscale = diffusescale;
1840                         // colorscale accounts for how much we multiply the brightness
1841                         // during combine.
1842                         //
1843                         // mult is how many times the final pass of the lighting will be
1844                         // performed to get more brightness than otherwise possible.
1845                         //
1846                         // Limit mult to 64 for sanity sake.
1847                         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1848                         {
1849                                 // 3/2 3D combine path (Geforce3, Radeon 8500)
1850                                 memset(&m, 0, sizeof(m));
1851                                 m.pointer_vertex = vertex3f;
1852                                 m.tex[0] = R_GetTexture(bumptexture);
1853                                 m.texcombinergb[0] = GL_REPLACE;
1854                                 m.pointer_texcoord[0] = texcoord2f;
1855                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1856                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1857                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1858                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1859                                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1860 #ifdef USETEXMATRIX
1861                                 m.pointer_texcoord3f[2] = vertex3f;
1862                                 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1863 #else
1864                                 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1865                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1866 #endif
1867                                 R_Mesh_State(&m);
1868                                 GL_ColorMask(0,0,0,1);
1869                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1870                                 GL_LockArrays(firstvertex, numvertices);
1871                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1872                                 GL_LockArrays(0, 0);
1873                                 c_rt_lightmeshes++;
1874                                 c_rt_lighttris += numtriangles;
1875
1876                                 memset(&m, 0, sizeof(m));
1877                                 m.pointer_vertex = vertex3f;
1878                                 m.tex[0] = R_GetTexture(basetexture);
1879                                 m.pointer_texcoord[0] = texcoord2f;
1880                                 if (lightcubemap)
1881                                 {
1882                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1883 #ifdef USETEXMATRIX
1884                                         m.pointer_texcoord3f[1] = vertex3f;
1885                                         m.texmatrix[1] = *matrix_modeltolight;
1886 #else
1887                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1888                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1889 #endif
1890                                 }
1891                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1892                         }
1893                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1894                         {
1895                                 // 1/2/2 3D combine path (original Radeon)
1896                                 memset(&m, 0, sizeof(m));
1897                                 m.pointer_vertex = vertex3f;
1898                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1899 #ifdef USETEXMATRIX
1900                                 m.pointer_texcoord3f[0] = vertex3f;
1901                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1902 #else
1903                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1904                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1905 #endif
1906                                 R_Mesh_State(&m);
1907                                 GL_ColorMask(0,0,0,1);
1908                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1909                                 GL_LockArrays(firstvertex, numvertices);
1910                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1911                                 GL_LockArrays(0, 0);
1912                                 c_rt_lightmeshes++;
1913                                 c_rt_lighttris += numtriangles;
1914
1915                                 memset(&m, 0, sizeof(m));
1916                                 m.pointer_vertex = vertex3f;
1917                                 m.tex[0] = R_GetTexture(bumptexture);
1918                                 m.texcombinergb[0] = GL_REPLACE;
1919                                 m.pointer_texcoord[0] = texcoord2f;
1920                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1921                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1922                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1923                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1924                                 R_Mesh_State(&m);
1925                                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1926                                 GL_LockArrays(firstvertex, numvertices);
1927                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1928                                 GL_LockArrays(0, 0);
1929                                 c_rt_lightmeshes++;
1930                                 c_rt_lighttris += numtriangles;
1931
1932                                 memset(&m, 0, sizeof(m));
1933                                 m.pointer_vertex = vertex3f;
1934                                 m.tex[0] = R_GetTexture(basetexture);
1935                                 m.pointer_texcoord[0] = texcoord2f;
1936                                 if (lightcubemap)
1937                                 {
1938                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1939 #ifdef USETEXMATRIX
1940                                         m.pointer_texcoord3f[1] = vertex3f;
1941                                         m.texmatrix[1] = *matrix_modeltolight;
1942 #else
1943                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1944                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1945 #endif
1946                                 }
1947                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1948                         }
1949                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1950                         {
1951                                 // 2/2 3D combine path (original Radeon)
1952                                 memset(&m, 0, sizeof(m));
1953                                 m.pointer_vertex = vertex3f;
1954                                 m.tex[0] = R_GetTexture(bumptexture);
1955                                 m.texcombinergb[0] = GL_REPLACE;
1956                                 m.pointer_texcoord[0] = texcoord2f;
1957                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1958                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1959                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1960                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1961                                 R_Mesh_State(&m);
1962                                 GL_ColorMask(0,0,0,1);
1963                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1964                                 GL_LockArrays(firstvertex, numvertices);
1965                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1966                                 GL_LockArrays(0, 0);
1967                                 c_rt_lightmeshes++;
1968                                 c_rt_lighttris += numtriangles;
1969
1970                                 memset(&m, 0, sizeof(m));
1971                                 m.pointer_vertex = vertex3f;
1972                                 m.tex[0] = R_GetTexture(basetexture);
1973                                 m.pointer_texcoord[0] = texcoord2f;
1974                                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1975 #ifdef USETEXMATRIX
1976                                 m.pointer_texcoord3f[1] = vertex3f;
1977                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1978 #else
1979                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1980                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1981 #endif
1982                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1983                         }
1984                         else if (r_textureunits.integer >= 4)
1985                         {
1986                                 // 4/2 2D combine path (Geforce3, Radeon 8500)
1987                                 memset(&m, 0, sizeof(m));
1988                                 m.pointer_vertex = vertex3f;
1989                                 m.tex[0] = R_GetTexture(bumptexture);
1990                                 m.texcombinergb[0] = GL_REPLACE;
1991                                 m.pointer_texcoord[0] = texcoord2f;
1992                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1993                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1994                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1995                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1996                                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1997 #ifdef USETEXMATRIX
1998                                 m.pointer_texcoord3f[2] = vertex3f;
1999                                 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2000 #else
2001                                 m.pointer_texcoord[2] = varray_texcoord2f[2];
2002                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2003 #endif
2004                                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2005 #ifdef USETEXMATRIX
2006                                 m.pointer_texcoord3f[3] = vertex3f;
2007                                 m.texmatrix[3] = *matrix_modeltoattenuationz;
2008 #else
2009                                 m.pointer_texcoord[3] = varray_texcoord2f[3];
2010                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2011 #endif
2012                                 R_Mesh_State(&m);
2013                                 GL_ColorMask(0,0,0,1);
2014                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2015                                 GL_LockArrays(firstvertex, numvertices);
2016                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2017                                 GL_LockArrays(0, 0);
2018                                 c_rt_lightmeshes++;
2019                                 c_rt_lighttris += numtriangles;
2020
2021                                 memset(&m, 0, sizeof(m));
2022                                 m.pointer_vertex = vertex3f;
2023                                 m.tex[0] = R_GetTexture(basetexture);
2024                                 m.pointer_texcoord[0] = texcoord2f;
2025                                 if (lightcubemap)
2026                                 {
2027                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
2028 #ifdef USETEXMATRIX
2029                                         m.pointer_texcoord3f[1] = vertex3f;
2030                                         m.texmatrix[1] = *matrix_modeltolight;
2031 #else
2032                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2033                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2034 #endif
2035                                 }
2036                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2037                         }
2038                         else
2039                         {
2040                                 // 2/2/2 2D combine path (any dot3 card)
2041                                 memset(&m, 0, sizeof(m));
2042                                 m.pointer_vertex = vertex3f;
2043                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2044 #ifdef USETEXMATRIX
2045                                 m.pointer_texcoord3f[0] = vertex3f;
2046                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2047 #else
2048                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
2049                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2050 #endif
2051                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2052 #ifdef USETEXMATRIX
2053                                 m.pointer_texcoord3f[1] = vertex3f;
2054                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
2055 #else
2056                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2057                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2058 #endif
2059                                 R_Mesh_State(&m);
2060                                 GL_ColorMask(0,0,0,1);
2061                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2062                                 GL_LockArrays(firstvertex, numvertices);
2063                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2064                                 GL_LockArrays(0, 0);
2065                                 c_rt_lightmeshes++;
2066                                 c_rt_lighttris += numtriangles;
2067
2068                                 memset(&m, 0, sizeof(m));
2069                                 m.pointer_vertex = vertex3f;
2070                                 m.tex[0] = R_GetTexture(bumptexture);
2071                                 m.texcombinergb[0] = GL_REPLACE;
2072                                 m.pointer_texcoord[0] = texcoord2f;
2073                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2074                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2075                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2076                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2077                                 R_Mesh_State(&m);
2078                                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2079                                 GL_LockArrays(firstvertex, numvertices);
2080                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2081                                 GL_LockArrays(0, 0);
2082                                 c_rt_lightmeshes++;
2083                                 c_rt_lighttris += numtriangles;
2084
2085                                 memset(&m, 0, sizeof(m));
2086                                 m.pointer_vertex = vertex3f;
2087                                 m.tex[0] = R_GetTexture(basetexture);
2088                                 m.pointer_texcoord[0] = texcoord2f;
2089                                 if (lightcubemap)
2090                                 {
2091                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
2092 #ifdef USETEXMATRIX
2093                                         m.pointer_texcoord3f[1] = vertex3f;
2094                                         m.texmatrix[1] = *matrix_modeltolight;
2095 #else
2096                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2097                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2098 #endif
2099                                 }
2100                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2101                         }
2102                         // this final code is shared
2103                         R_Mesh_State(&m);
2104                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2105                         VectorScale(lightcolor, colorscale, color2);
2106                         GL_LockArrays(firstvertex, numvertices);
2107                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2108                         {
2109                                 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2110                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2111                                 c_rt_lightmeshes++;
2112                                 c_rt_lighttris += numtriangles;
2113                         }
2114                         GL_LockArrays(0, 0);
2115                 }
2116                 if (specularscale && glosstexture != r_texture_black)
2117                 {
2118                         // FIXME: detect blendsquare!
2119                         //if (gl_support_blendsquare)
2120                         {
2121                                 colorscale = specularscale;
2122                                 GL_Color(1,1,1,1);
2123                                 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2124                                 {
2125                                         // 2/0/0/1/2 3D combine blendsquare path
2126                                         memset(&m, 0, sizeof(m));
2127                                         m.pointer_vertex = vertex3f;
2128                                         m.tex[0] = R_GetTexture(bumptexture);
2129                                         m.pointer_texcoord[0] = texcoord2f;
2130                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2131                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2132                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2133                                         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);
2134                                         R_Mesh_State(&m);
2135                                         GL_ColorMask(0,0,0,1);
2136                                         // this squares the result
2137                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2138                                         GL_LockArrays(firstvertex, numvertices);
2139                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2140                                         GL_LockArrays(0, 0);
2141                                         c_rt_lightmeshes++;
2142                                         c_rt_lighttris += numtriangles;
2143
2144                                         memset(&m, 0, sizeof(m));
2145                                         m.pointer_vertex = vertex3f;
2146                                         R_Mesh_State(&m);
2147                                         GL_LockArrays(firstvertex, numvertices);
2148                                         // square alpha in framebuffer a few times to make it shiny
2149                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2150                                         // these comments are a test run through this math for intensity 0.5
2151                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2152                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2153                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2154                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2155                                         c_rt_lightmeshes++;
2156                                         c_rt_lighttris += numtriangles;
2157                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2158                                         c_rt_lightmeshes++;
2159                                         c_rt_lighttris += numtriangles;
2160                                         GL_LockArrays(0, 0);
2161
2162                                         memset(&m, 0, sizeof(m));
2163                                         m.pointer_vertex = vertex3f;
2164                                         m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2165 #ifdef USETEXMATRIX
2166                                         m.pointer_texcoord3f[0] = vertex3f;
2167                                         m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2168 #else
2169                                         m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2170                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2171 #endif
2172                                         R_Mesh_State(&m);
2173                                         GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2174                                         GL_LockArrays(firstvertex, numvertices);
2175                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2176                                         GL_LockArrays(0, 0);
2177                                         c_rt_lightmeshes++;
2178                                         c_rt_lighttris += numtriangles;
2179
2180                                         memset(&m, 0, sizeof(m));
2181                                         m.pointer_vertex = vertex3f;
2182                                         m.tex[0] = R_GetTexture(glosstexture);
2183                                         m.pointer_texcoord[0] = texcoord2f;
2184                                         if (lightcubemap)
2185                                         {
2186                                                 m.texcubemap[1] = R_GetTexture(lightcubemap);
2187 #ifdef USETEXMATRIX
2188                                                 m.pointer_texcoord3f[1] = vertex3f;
2189                                                 m.texmatrix[1] = *matrix_modeltolight;
2190 #else
2191                                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2192                                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2193 #endif
2194                                         }
2195                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2196                                 }
2197                                 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2198                                 {
2199                                         // 2/0/0/2 3D combine blendsquare path
2200                                         memset(&m, 0, sizeof(m));
2201                                         m.pointer_vertex = vertex3f;
2202                                         m.tex[0] = R_GetTexture(bumptexture);
2203                                         m.pointer_texcoord[0] = texcoord2f;
2204                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2205                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2206                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2207                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2208                                         R_Mesh_State(&m);
2209                                         GL_ColorMask(0,0,0,1);
2210                                         // this squares the result
2211                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2212                                         GL_LockArrays(firstvertex, numvertices);
2213                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2214                                         GL_LockArrays(0, 0);
2215                                         c_rt_lightmeshes++;
2216                                         c_rt_lighttris += numtriangles;
2217
2218                                         memset(&m, 0, sizeof(m));
2219                                         m.pointer_vertex = vertex3f;
2220                                         R_Mesh_State(&m);
2221                                         GL_LockArrays(firstvertex, numvertices);
2222                                         // square alpha in framebuffer a few times to make it shiny
2223                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2224                                         // these comments are a test run through this math for intensity 0.5
2225                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2226                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2227                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2228                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2229                                         c_rt_lightmeshes++;
2230                                         c_rt_lighttris += numtriangles;
2231                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2232                                         c_rt_lightmeshes++;
2233                                         c_rt_lighttris += numtriangles;
2234                                         GL_LockArrays(0, 0);
2235
2236                                         memset(&m, 0, sizeof(m));
2237                                         m.pointer_vertex = vertex3f;
2238                                         m.tex[0] = R_GetTexture(glosstexture);
2239                                         m.pointer_texcoord[0] = texcoord2f;
2240                                         m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2241 #ifdef USETEXMATRIX
2242                                         m.pointer_texcoord3f[1] = vertex3f;
2243                                         m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2244 #else
2245                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2246                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2247 #endif
2248                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2249                                 }
2250                                 else
2251                                 {
2252                                         // 2/0/0/2/2 2D combine blendsquare path
2253                                         memset(&m, 0, sizeof(m));
2254                                         m.pointer_vertex = vertex3f;
2255                                         m.tex[0] = R_GetTexture(bumptexture);
2256                                         m.pointer_texcoord[0] = texcoord2f;
2257                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2258                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2259                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2260                                         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);
2261                                         R_Mesh_State(&m);
2262                                         GL_ColorMask(0,0,0,1);
2263                                         // this squares the result
2264                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2265                                         GL_LockArrays(firstvertex, numvertices);
2266                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2267                                         GL_LockArrays(0, 0);
2268                                         c_rt_lightmeshes++;
2269                                         c_rt_lighttris += numtriangles;
2270
2271                                         memset(&m, 0, sizeof(m));
2272                                         m.pointer_vertex = vertex3f;
2273                                         R_Mesh_State(&m);
2274                                         GL_LockArrays(firstvertex, numvertices);
2275                                         // square alpha in framebuffer a few times to make it shiny
2276                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2277                                         // these comments are a test run through this math for intensity 0.5
2278                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2279                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2280                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2281                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2282                                         c_rt_lightmeshes++;
2283                                         c_rt_lighttris += numtriangles;
2284                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2285                                         c_rt_lightmeshes++;
2286                                         c_rt_lighttris += numtriangles;
2287                                         GL_LockArrays(0, 0);
2288
2289                                         memset(&m, 0, sizeof(m));
2290                                         m.pointer_vertex = vertex3f;
2291                                         m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2292 #ifdef USETEXMATRIX
2293                                         m.pointer_texcoord3f[0] = vertex3f;
2294                                         m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2295 #else
2296                                         m.pointer_texcoord[0] = varray_texcoord2f[0];
2297                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2298 #endif
2299                                         m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2300 #ifdef USETEXMATRIX
2301                                         m.pointer_texcoord3f[1] = vertex3f;
2302                                         m.texmatrix[1] = *matrix_modeltoattenuationz;
2303 #else
2304                                         m.pointer_texcoord[1] = varray_texcoord2f[1];
2305                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2306 #endif
2307                                         R_Mesh_State(&m);
2308                                         GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2309                                         GL_LockArrays(firstvertex, numvertices);
2310                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2311                                         GL_LockArrays(0, 0);
2312                                         c_rt_lightmeshes++;
2313                                         c_rt_lighttris += numtriangles;
2314
2315                                         memset(&m, 0, sizeof(m));
2316                                         m.pointer_vertex = vertex3f;
2317                                         m.tex[0] = R_GetTexture(glosstexture);
2318                                         m.pointer_texcoord[0] = texcoord2f;
2319                                         if (lightcubemap)
2320                                         {
2321                                                 m.texcubemap[1] = R_GetTexture(lightcubemap);
2322 #ifdef USETEXMATRIX
2323                                                 m.pointer_texcoord3f[1] = vertex3f;
2324                                                 m.texmatrix[1] = *matrix_modeltolight;
2325 #else
2326                                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2327                                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2328 #endif
2329                                         }
2330                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2331                                 }
2332                                 R_Mesh_State(&m);
2333                                 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2334                                 VectorScale(lightcolor, colorscale, color2);
2335                                 GL_LockArrays(firstvertex, numvertices);
2336                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2337                                 {
2338                                         GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2339                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2340                                         c_rt_lightmeshes++;
2341                                         c_rt_lighttris += numtriangles;
2342                                 }
2343                                 GL_LockArrays(0, 0);
2344                         }
2345                 }
2346         }
2347         else
2348         {
2349                 if (ambientscale)
2350                 {
2351                         GL_BlendFunc(GL_ONE, GL_ONE);
2352                         VectorScale(lightcolor, ambientscale, color2);
2353                         memset(&m, 0, sizeof(m));
2354                         m.pointer_vertex = vertex3f;
2355                         m.tex[0] = R_GetTexture(basetexture);
2356                         m.pointer_texcoord[0] = texcoord2f;
2357                         if (r_textureunits.integer >= 2)
2358                         {
2359                                 // voodoo2
2360                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2361 #ifdef USETEXMATRIX
2362                                 m.pointer_texcoord3f[1] = vertex3f;
2363                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2364 #else
2365                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2366                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2367 #endif
2368                                 if (r_textureunits.integer >= 3)
2369                                 {
2370                                         // Geforce3/Radeon class but not using dot3
2371                                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2372 #ifdef USETEXMATRIX
2373                                         m.pointer_texcoord3f[2] = vertex3f;
2374                                         m.texmatrix[2] = *matrix_modeltoattenuationz;
2375 #else
2376                                         m.pointer_texcoord[2] = varray_texcoord2f[2];
2377                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2378 #endif
2379                                 }
2380                         }
2381                         if (r_textureunits.integer >= 3)
2382                                 m.pointer_color = NULL;
2383                         else
2384                                 m.pointer_color = varray_color4f;
2385                         R_Mesh_State(&m);
2386                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2387                         {
2388                                 color[0] = bound(0, color2[0], 1);
2389                                 color[1] = bound(0, color2[1], 1);
2390                                 color[2] = bound(0, color2[2], 1);
2391                                 if (r_textureunits.integer >= 3)
2392                                         GL_Color(color[0], color[1], color[2], 1);
2393                                 else if (r_textureunits.integer >= 2)
2394                                         R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2395                                 else
2396                                         R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2397                                 GL_LockArrays(firstvertex, numvertices);
2398                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2399                                 GL_LockArrays(0, 0);
2400                                 c_rt_lightmeshes++;
2401                                 c_rt_lighttris += numtriangles;
2402                         }
2403                 }
2404                 if (diffusescale)
2405                 {
2406                         GL_BlendFunc(GL_ONE, GL_ONE);
2407                         VectorScale(lightcolor, diffusescale, color2);
2408                         memset(&m, 0, sizeof(m));
2409                         m.pointer_vertex = vertex3f;
2410                         m.pointer_color = varray_color4f;
2411                         m.tex[0] = R_GetTexture(basetexture);
2412                         m.pointer_texcoord[0] = texcoord2f;
2413                         if (r_textureunits.integer >= 2)
2414                         {
2415                                 // voodoo2
2416                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2417 #ifdef USETEXMATRIX
2418                                 m.pointer_texcoord3f[1] = vertex3f;
2419                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2420 #else
2421                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2422                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2423 #endif
2424                                 if (r_textureunits.integer >= 3)
2425                                 {
2426                                         // Geforce3/Radeon class but not using dot3
2427                                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2428 #ifdef USETEXMATRIX
2429                                         m.pointer_texcoord3f[2] = vertex3f;
2430                                         m.texmatrix[2] = *matrix_modeltoattenuationz;
2431 #else
2432                                         m.pointer_texcoord[2] = varray_texcoord2f[2];
2433                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2434 #endif
2435                                 }
2436                         }
2437                         R_Mesh_State(&m);
2438                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2439                         {
2440                                 color[0] = bound(0, color2[0], 1);
2441                                 color[1] = bound(0, color2[1], 1);
2442                                 color[2] = bound(0, color2[2], 1);
2443                                 if (r_textureunits.integer >= 3)
2444                                         R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2445                                 else if (r_textureunits.integer >= 2)
2446                                         R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2447                                 else
2448                                         R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2449                                 GL_LockArrays(firstvertex, numvertices);
2450                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2451                                 GL_LockArrays(0, 0);
2452                                 c_rt_lightmeshes++;
2453                                 c_rt_lighttris += numtriangles;
2454                         }
2455                 }
2456         }
2457 }
2458
2459 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2460 {
2461         int j, k;
2462         float scale;
2463         R_RTLight_Uncompile(rtlight);
2464         memset(rtlight, 0, sizeof(*rtlight));
2465
2466         VectorCopy(light->origin, rtlight->shadoworigin);
2467         VectorCopy(light->color, rtlight->color);
2468         rtlight->radius = light->radius;
2469         //rtlight->cullradius = rtlight->radius;
2470         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2471         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2472         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2473         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2474         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2475         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2476         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2477         rtlight->cubemapname[0] = 0;
2478         if (light->cubemapname[0])
2479                 strcpy(rtlight->cubemapname, light->cubemapname);
2480         else if (light->cubemapnum > 0)
2481                 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2482         rtlight->shadow = light->shadow;
2483         rtlight->corona = light->corona;
2484         rtlight->style = light->style;
2485         rtlight->isstatic = isstatic;
2486         rtlight->coronasizescale = light->coronasizescale;
2487         rtlight->ambientscale = light->ambientscale;
2488         rtlight->diffusescale = light->diffusescale;
2489         rtlight->specularscale = light->specularscale;
2490         rtlight->flags = light->flags;
2491         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2492         // ConcatScale won't work here because this needs to scale rotate and
2493         // translate, not just rotate
2494         scale = 1.0f / rtlight->radius;
2495         for (k = 0;k < 3;k++)
2496                 for (j = 0;j < 4;j++)
2497                         rtlight->matrix_worldtolight.m[k][j] *= scale;
2498         Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2499         Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2500
2501         rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2502         rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2503         VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2504         rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2505 }
2506
2507 // compiles rtlight geometry
2508 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2509 void R_RTLight_Compile(rtlight_t *rtlight)
2510 {
2511         int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2512         entity_render_t *ent = r_refdef.worldentity;
2513         model_t *model = r_refdef.worldmodel;
2514
2515         // compile the light
2516         rtlight->compiled = true;
2517         rtlight->static_numclusters = 0;
2518         rtlight->static_numclusterpvsbytes = 0;
2519         rtlight->static_clusterlist = NULL;
2520         rtlight->static_clusterpvs = NULL;
2521         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2522         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2523         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2524         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2525         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2526         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2527
2528         if (model && model->GetLightInfo)
2529         {
2530                 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2531                 r_shadow_compilingrtlight = rtlight;
2532                 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2533                 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2534                 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);
2535                 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2536                 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2537                 if (numclusters)
2538                 {
2539                         rtlight->static_numclusters = numclusters;
2540                         rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2541                         memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2542                         memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2543                 }
2544                 if (model->DrawShadowVolume && rtlight->shadow)
2545                 {
2546                         rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2547                         model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2548                         rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2549                 }
2550                 if (model->DrawLight)
2551                 {
2552                         rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2553                         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);
2554                         rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2555                 }
2556                 // switch back to rendering when DrawShadowVolume or DrawLight is called
2557                 r_shadow_compilingrtlight = NULL;
2558         }
2559
2560
2561         // use smallest available cullradius - box radius or light radius
2562         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2563         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2564
2565         shadowmeshes = 0;
2566         shadowtris = 0;
2567         if (rtlight->static_meshchain_shadow)
2568         {
2569                 shadowmesh_t *mesh;
2570                 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2571                 {
2572                         shadowmeshes++;
2573                         shadowtris += mesh->numtriangles;
2574                 }
2575         }
2576
2577         lightmeshes = 0;
2578         lighttris = 0;
2579         if (rtlight->static_meshchain_light)
2580         {
2581                 shadowmesh_t *mesh;
2582                 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2583                 {
2584                         lightmeshes++;
2585                         lighttris += mesh->numtriangles;
2586                 }
2587         }
2588
2589         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);
2590 }
2591
2592 void R_RTLight_Uncompile(rtlight_t *rtlight)
2593 {
2594         if (rtlight->compiled)
2595         {
2596                 if (rtlight->static_meshchain_shadow)
2597                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2598                 rtlight->static_meshchain_shadow = NULL;
2599                 if (rtlight->static_meshchain_light)
2600                         Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2601                 rtlight->static_meshchain_light = NULL;
2602                 if (rtlight->static_clusterlist)
2603                         Mem_Free(rtlight->static_clusterlist);
2604                 rtlight->static_clusterlist = NULL;
2605                 if (rtlight->static_clusterpvs)
2606                         Mem_Free(rtlight->static_clusterpvs);
2607                 rtlight->static_clusterpvs = NULL;
2608                 rtlight->static_numclusters = 0;
2609                 rtlight->static_numclusterpvsbytes = 0;
2610                 rtlight->compiled = false;
2611         }
2612 }
2613
2614 void R_Shadow_UncompileWorldLights(void)
2615 {
2616         dlight_t *light;
2617         for (light = r_shadow_worldlightchain;light;light = light->next)
2618                 R_RTLight_Uncompile(&light->rtlight);
2619 }
2620
2621 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2622 {
2623         int i, shadow, usestencil;
2624         entity_render_t *ent;
2625         float f;
2626         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2627         rtexture_t *cubemaptexture;
2628         matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2629         int numclusters, numsurfaces;
2630         int *clusterlist, *surfacelist;
2631         qbyte *clusterpvs;
2632         vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2633         shadowmesh_t *mesh;
2634         rmeshstate_t m;
2635
2636         // skip lights that don't light (corona only lights)
2637         if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2638                 return;
2639
2640         f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2641         VectorScale(rtlight->color, f, lightcolor);
2642         if (VectorLength2(lightcolor) < 0.01)
2643                 return;
2644         /*
2645         if (rtlight->selected)
2646         {
2647                 f = 2 + sin(realtime * M_PI * 4.0);
2648                 VectorScale(lightcolor, f, lightcolor);
2649         }
2650         */
2651
2652         // loading is done before visibility checks because loading should happen
2653         // all at once at the start of a level, not when it stalls gameplay.
2654         // (especially important to benchmarks)
2655         if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2656                 R_RTLight_Compile(rtlight);
2657         if (rtlight->cubemapname[0])
2658                 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2659         else
2660                 cubemaptexture = NULL;
2661
2662         cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2663         cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2664         cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2665         cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2666         cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2667         cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2668         if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2669                 return;
2670         numclusters = 0;
2671         clusterlist = NULL;
2672         clusterpvs = NULL;
2673         numsurfaces = 0;
2674         surfacelist = NULL;
2675         if (rtlight->compiled && r_shadow_staticworldlights.integer)
2676         {
2677                 // compiled light, world available and can receive realtime lighting
2678                 // retrieve cluster information
2679                 numclusters = rtlight->static_numclusters;
2680                 clusterlist = rtlight->static_clusterlist;
2681                 clusterpvs = rtlight->static_clusterpvs;
2682                 VectorCopy(rtlight->cullmins, cullmins);
2683                 VectorCopy(rtlight->cullmaxs, cullmaxs);
2684         }
2685         else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2686         {
2687                 // dynamic light, world available and can receive realtime lighting
2688                 // if the light box is offscreen, skip it right away
2689                 if (R_CullBox(cullmins, cullmaxs))
2690                         return;
2691                 // calculate lit surfaces and clusters
2692                 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2693                 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2694                 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);
2695                 clusterlist = r_shadow_buffer_clusterlist;
2696                 clusterpvs = r_shadow_buffer_clusterpvs;
2697                 surfacelist = r_shadow_buffer_surfacelist;
2698         }
2699         // if the reduced cluster bounds are offscreen, skip it
2700         if (R_CullBox(cullmins, cullmaxs))
2701                 return;
2702         // check if light is illuminating any visible clusters
2703         if (numclusters)
2704         {
2705                 for (i = 0;i < numclusters;i++)
2706                         if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2707                                 break;
2708                 if (i == numclusters)
2709                         return;
2710         }
2711         // set up a scissor rectangle for this light
2712         if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2713                 return;
2714
2715         shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2716         usestencil = false;
2717
2718         if (shadow && (gl_stencil || visiblevolumes))
2719         {
2720                 if (!visiblevolumes)
2721                 {
2722                         R_Shadow_Stage_ShadowVolumes();
2723                         usestencil = true;
2724                 }
2725                 ent = r_refdef.worldentity;
2726                 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2727                 {
2728                         memset(&m, 0, sizeof(m));
2729                         R_Mesh_Matrix(&ent->matrix);
2730                         for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2731                         {
2732                                 m.pointer_vertex = mesh->vertex3f;
2733                                 R_Mesh_State(&m);
2734                                 GL_LockArrays(0, mesh->numverts);
2735                                 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2736                                 {
2737                                         // increment stencil if backface is behind depthbuffer
2738                                         qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2739                                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2740                                         R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2741                                         c_rtcached_shadowmeshes++;
2742                                         c_rtcached_shadowtris += mesh->numtriangles;
2743                                         // decrement stencil if frontface is behind depthbuffer
2744                                         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2745                                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2746                                 }
2747                                 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2748                                 c_rtcached_shadowmeshes++;
2749                                 c_rtcached_shadowtris += mesh->numtriangles;
2750                                 GL_LockArrays(0, 0);
2751                         }
2752                 }
2753                 else if (numsurfaces)
2754                 {
2755                         Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2756                         ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2757                 }
2758                 if (r_drawentities.integer)
2759                 {
2760                         for (i = 0;i < r_refdef.numentities;i++)
2761                         {
2762                                 ent = r_refdef.entities[i];
2763                                 // rough checks
2764                                 if (r_shadow_cull.integer)
2765                                 {
2766                                         if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2767                                                 continue;
2768                                         if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2769                                                 continue;
2770                                 }
2771                                 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2772                                         continue;
2773                                 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2774                                 // light emitting entities should not cast their own shadow
2775                                 if (VectorLength2(relativelightorigin) < 0.1)
2776                                         continue;
2777                                 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2778                                 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2779                                 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2780                                 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2781                                 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2782                                 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2783                                 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2784                         }
2785                 }
2786         }
2787
2788         if (!visiblevolumes)
2789         {
2790                 R_Shadow_Stage_Light(usestencil);
2791
2792                 ent = r_refdef.worldentity;
2793                 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2794                 {
2795                         lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2796                         lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2797                         lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2798                         Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2799                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2800                         Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2801                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2802                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2803                         if (r_shadow_staticworldlights.integer && rtlight->compiled)
2804                         {
2805                                 R_Mesh_Matrix(&ent->matrix);
2806                                 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2807                                         R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
2808                         }
2809                         else
2810                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2811                 }
2812                 if (r_drawentities.integer)
2813                 {
2814                         for (i = 0;i < r_refdef.numentities;i++)
2815                         {
2816                                 ent = r_refdef.entities[i];
2817                                 // can't draw transparent entity lighting here because
2818                                 // transparent meshes are deferred for later
2819                                 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)
2820                                 {
2821                                         lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2822                                         lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2823                                         lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2824                                         Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2825                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2826                                         Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2827                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2828                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2829                                         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);
2830                                 }
2831                         }
2832                 }
2833         }
2834 }
2835
2836 void R_ShadowVolumeLighting(int visiblevolumes)
2837 {
2838         int lnum, flag;
2839         dlight_t *light;
2840         rmeshstate_t m;
2841
2842         if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2843                 R_Shadow_EditLights_Reload_f();
2844
2845         if (visiblevolumes)
2846         {
2847                 memset(&m, 0, sizeof(m));
2848                 R_Mesh_State(&m);
2849
2850                 GL_BlendFunc(GL_ONE, GL_ONE);
2851                 GL_DepthMask(false);
2852                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2853                 qglDisable(GL_CULL_FACE);
2854                 GL_Color(0.0, 0.0125, 0.1, 1);
2855         }
2856         else
2857                 R_Shadow_Stage_Begin();
2858         flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2859         if (r_shadow_debuglight.integer >= 0)
2860         {
2861                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2862                         if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2863                                 R_DrawRTLight(&light->rtlight, visiblevolumes);
2864         }
2865         else
2866                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2867                         if (light->flags & flag)
2868                                 R_DrawRTLight(&light->rtlight, visiblevolumes);
2869         if (r_rtdlight)
2870                 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2871                         R_DrawRTLight(&light->rtlight, visiblevolumes);
2872
2873         if (visiblevolumes)
2874         {
2875                 qglEnable(GL_CULL_FACE);
2876                 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2877         }
2878         else
2879                 R_Shadow_Stage_End();
2880 }
2881
2882 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2883 typedef struct suffixinfo_s
2884 {
2885         char *suffix;
2886         qboolean flipx, flipy, flipdiagonal;
2887 }
2888 suffixinfo_t;
2889 static suffixinfo_t suffix[3][6] =
2890 {
2891         {
2892                 {"px",   false, false, false},
2893                 {"nx",   false, false, false},
2894                 {"py",   false, false, false},
2895                 {"ny",   false, false, false},
2896                 {"pz",   false, false, false},
2897                 {"nz",   false, false, false}
2898         },
2899         {
2900                 {"posx", false, false, false},
2901                 {"negx", false, false, false},
2902                 {"posy", false, false, false},
2903                 {"negy", false, false, false},
2904                 {"posz", false, false, false},
2905                 {"negz", false, false, false}
2906         },
2907         {
2908                 {"rt",    true, false,  true},
2909                 {"lf",   false,  true,  true},
2910                 {"ft",    true,  true, false},
2911                 {"bk",   false, false, false},
2912                 {"up",    true, false,  true},
2913