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