]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
added rmesh_t and R_Mesh_AddVertex3f, R_Mesh_AddPolygon3f, R_Mesh_AddBrushMeshFromPla...
[xonotic/darkplaces.git] / r_shadow.c
1
2 /*
3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
9
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
15
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
20
21 Patent warning:
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
26 shadows do not lie.
27
28
29
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contains the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
36
37
38
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
44 in some ideal cases).
45
46
47
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however.  Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
57
58
59
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
65
66
67
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
76
77
78
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
82
83
84
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
89
90
91
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
96
97
98
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
105
106
107
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
112 */
113
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
117 #include "portals.h"
118 #include "image.h"
119
120 extern void R_Shadow_EditLights_Init(void);
121
122 typedef enum r_shadowstage_e
123 {
124         R_SHADOWSTAGE_NONE,
125         R_SHADOWSTAGE_STENCIL,
126         R_SHADOWSTAGE_STENCILTWOSIDE,
127         R_SHADOWSTAGE_LIGHT_VERTEX,
128         R_SHADOWSTAGE_LIGHT_DOT3,
129         R_SHADOWSTAGE_LIGHT_GLSL,
130         R_SHADOWSTAGE_VISIBLEVOLUMES,
131         R_SHADOWSTAGE_VISIBLELIGHTING,
132 }
133 r_shadowstage_t;
134
135 r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
136
137 mempool_t *r_shadow_mempool;
138
139 int maxshadowelements;
140 int *shadowelements;
141
142 int maxshadowmark;
143 int numshadowmark;
144 int *shadowmark;
145 int *shadowmarklist;
146 int shadowmarkcount;
147
148 int maxvertexupdate;
149 int *vertexupdate;
150 int *vertexremap;
151 int vertexupdatenum;
152
153 int r_shadow_buffer_numleafpvsbytes;
154 qbyte *r_shadow_buffer_leafpvs;
155 int *r_shadow_buffer_leaflist;
156
157 int r_shadow_buffer_numsurfacepvsbytes;
158 qbyte *r_shadow_buffer_surfacepvs;
159 int *r_shadow_buffer_surfacelist;
160
161 rtexturepool_t *r_shadow_texturepool;
162 rtexture_t *r_shadow_attenuation2dtexture;
163 rtexture_t *r_shadow_attenuation3dtexture;
164
165 // lights are reloaded when this changes
166 char r_shadow_mapname[MAX_QPATH];
167
168 // used only for light filters (cubemaps)
169 rtexturepool_t *r_shadow_filters_texturepool;
170
171 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
172 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
173 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
174 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
175 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
176 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
177 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
178 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
179 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
180 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
181 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
182 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
183 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
184 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
185 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
186 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
187 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
188 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
189 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
190 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
191 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
192 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
193 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
194 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
195 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
196 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
197 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
198 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
199 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
200 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
201 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
202 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
203 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
204 cvar_t r_editlights = {0, "r_editlights", "0"};
205 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
206 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
207 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
208 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
209 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
210 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
211 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
212
213 float r_shadow_attenpower, r_shadow_attenscale;
214
215 rtlight_t *r_shadow_compilingrtlight;
216 dlight_t *r_shadow_worldlightchain;
217 dlight_t *r_shadow_selectedlight;
218 dlight_t r_shadow_bufferlight;
219 vec3_t r_editlights_cursorlocation;
220
221 rtexture_t *lighttextures[5];
222
223 extern int con_vislines;
224
225 typedef struct cubemapinfo_s
226 {
227         char basename[64];
228         rtexture_t *texture;
229 }
230 cubemapinfo_t;
231
232 #define MAX_CUBEMAPS 256
233 static int numcubemaps;
234 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
235
236 #define SHADERPERMUTATION_SPECULAR (1<<0)
237 #define SHADERPERMUTATION_FOG (1<<1)
238 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
239 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
240 #define SHADERPERMUTATION_COUNT (1<<4)
241
242 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
243
244 void R_Shadow_UncompileWorldLights(void);
245 void R_Shadow_ClearWorldLights(void);
246 void R_Shadow_SaveWorldLights(void);
247 void R_Shadow_LoadWorldLights(void);
248 void R_Shadow_LoadLightsFile(void);
249 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
250 void R_Shadow_EditLights_Reload_f(void);
251 void R_Shadow_ValidateCvars(void);
252 static void R_Shadow_MakeTextures(void);
253 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
254
255 const char *builtinshader_light_vert =
256 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
257 "// written by Forest 'LordHavoc' Hale\n"
258 "\n"
259 "uniform vec3 LightPosition;\n"
260 "\n"
261 "varying vec2 TexCoord;\n"
262 "varying vec3 CubeVector;\n"
263 "varying vec3 LightVector;\n"
264 "\n"
265 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
266 "uniform vec3 EyePosition;\n"
267 "varying vec3 EyeVector;\n"
268 "#endif\n"
269 "\n"
270 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
271 "\n"
272 "void main(void)\n"
273 "{\n"
274 "       // copy the surface texcoord\n"
275 "       TexCoord = gl_MultiTexCoord0.st;\n"
276 "\n"
277 "       // transform vertex position into light attenuation/cubemap space\n"
278 "       // (-1 to +1 across the light box)\n"
279 "       CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
280 "\n"
281 "       // transform unnormalized light direction into tangent space\n"
282 "       // (we use unnormalized to ensure that it interpolates correctly and then\n"
283 "       //  normalize it per pixel)\n"
284 "       vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
285 "       LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
286 "       LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
287 "       LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
288 "\n"
289 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
290 "       // transform unnormalized eye direction into tangent space\n"
291 "       vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
292 "       EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
293 "       EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
294 "       EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
295 "#endif\n"
296 "\n"
297 "       // transform vertex to camera space, using ftransform to match non-VS\n"
298 "       // rendering\n"
299 "       gl_Position = ftransform();\n"
300 "}\n"
301 ;
302
303 const char *builtinshader_light_frag =
304 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
305 "// written by Forest 'LordHavoc' Hale\n"
306 "\n"
307 "uniform vec3 LightColor;\n"
308 "\n"
309 "#ifdef USEOFFSETMAPPING\n"
310 "uniform float OffsetMapping_Scale;\n"
311 "uniform float OffsetMapping_Bias;\n"
312 "#endif\n"
313 "#ifdef USESPECULAR\n"
314 "uniform float SpecularPower;\n"
315 "#endif\n"
316 "#ifdef USEFOG\n"
317 "uniform float FogRangeRecip;\n"
318 "#endif\n"
319 "uniform float AmbientScale;\n"
320 "uniform float DiffuseScale;\n"
321 "#ifdef USESPECULAR\n"
322 "uniform float SpecularScale;\n"
323 "#endif\n"
324 "\n"
325 "uniform sampler2D Texture_Normal;\n"
326 "uniform sampler2D Texture_Color;\n"
327 "#ifdef USESPECULAR\n"
328 "uniform sampler2D Texture_Gloss;\n"
329 "#endif\n"
330 "#ifdef USECUBEFILTER\n"
331 "uniform samplerCube Texture_Cube;\n"
332 "#endif\n"
333 "#ifdef USEFOG\n"
334 "uniform sampler2D Texture_FogMask;\n"
335 "#endif\n"
336 "\n"
337 "varying vec2 TexCoord;\n"
338 "varying vec3 CubeVector;\n"
339 "varying vec3 LightVector;\n"
340 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
341 "varying vec3 EyeVector;\n"
342 "#endif\n"
343 "\n"
344 "void main(void)\n"
345 "{\n"
346 "       // attenuation\n"
347 "       //\n"
348 "       // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
349 "       // center and sharp falloff at the edge, this is about the most efficient\n"
350 "       // we can get away with as far as providing illumination.\n"
351 "       //\n"
352 "       // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
353 "       // provide significant illumination, large = slow = pain.\n"
354 "       float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
355 "\n"
356 "#ifdef USEFOG\n"
357 "       // apply fog\n"
358 "       colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
359 "#endif\n"
360 "\n"
361 "#ifdef USEOFFSETMAPPING\n"
362 "       // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
363 "       vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
364 "       vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
365 "       TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
366 "       TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
367 "#define TexCoord TexCoordOffset\n"
368 "#endif\n"
369 "\n"
370 "       // get the texels - with a blendmap we'd need to blend multiple here\n"
371 "       vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
372 "       vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
373 "#ifdef USESPECULAR\n"
374 "       vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
375 "#endif\n"
376 "\n"
377 "       // calculate shading\n"
378 "       vec3 diffusenormal = normalize(LightVector);\n"
379 "       vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
380 "#ifdef USESPECULAR\n"
381 "       color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
382 "#endif\n"
383 "\n"
384 "#ifdef USECUBEFILTER\n"
385 "       // apply light cubemap filter\n"
386 "       color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
387 "#endif\n"
388 "\n"
389 "       // calculate fragment color\n"
390 "       gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
391 "}\n"
392 ;
393
394 void r_shadow_start(void)
395 {
396         int i;
397         // allocate vertex processing arrays
398         numcubemaps = 0;
399         r_shadow_attenuation2dtexture = NULL;
400         r_shadow_attenuation3dtexture = NULL;
401         r_shadow_texturepool = NULL;
402         r_shadow_filters_texturepool = NULL;
403         R_Shadow_ValidateCvars();
404         R_Shadow_MakeTextures();
405         maxshadowelements = 0;
406         shadowelements = NULL;
407         maxvertexupdate = 0;
408         vertexupdate = NULL;
409         vertexremap = NULL;
410         vertexupdatenum = 0;
411         maxshadowmark = 0;
412         numshadowmark = 0;
413         shadowmark = NULL;
414         shadowmarklist = NULL;
415         shadowmarkcount = 0;
416         r_shadow_buffer_numleafpvsbytes = 0;
417         r_shadow_buffer_leafpvs = NULL;
418         r_shadow_buffer_leaflist = NULL;
419         r_shadow_buffer_numsurfacepvsbytes = 0;
420         r_shadow_buffer_surfacepvs = NULL;
421         r_shadow_buffer_surfacelist = NULL;
422         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
423                 r_shadow_program_light[i] = 0;
424         if (gl_support_fragment_shader)
425         {
426                 char *vertstring, *fragstring;
427                 int vertstrings_count;
428                 int fragstrings_count;
429                 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
430                 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
431                 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
432                 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
433                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
434                 {
435                         vertstrings_count = 0;
436                         fragstrings_count = 0;
437                         if (i & SHADERPERMUTATION_SPECULAR)
438                         {
439                                 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
440                                 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
441                         }
442                         if (i & SHADERPERMUTATION_FOG)
443                         {
444                                 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
445                                 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
446                         }
447                         if (i & SHADERPERMUTATION_CUBEFILTER)
448                         {
449                                 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
450                                 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
451                         }
452                         if (i & SHADERPERMUTATION_OFFSETMAPPING)
453                         {
454                                 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
455                                 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
456                         }
457                         vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
458                         fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
459                         r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
460                         if (!r_shadow_program_light[i])
461                         {
462                                 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
463                                 continue;
464                         }
465                         qglUseProgramObjectARB(r_shadow_program_light[i]);
466                         qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
467                         qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
468                         if (i & SHADERPERMUTATION_SPECULAR)
469                         {
470                                 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
471                         }
472                         if (i & SHADERPERMUTATION_CUBEFILTER)
473                         {
474                                 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
475                         }
476                         if (i & SHADERPERMUTATION_FOG)
477                         {
478                                 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
479                         }
480                 }
481                 qglUseProgramObjectARB(0);
482                 if (fragstring)
483                         Mem_Free(fragstring);
484                 if (vertstring)
485                         Mem_Free(vertstring);
486         }
487 }
488
489 void r_shadow_shutdown(void)
490 {
491         int i;
492         R_Shadow_UncompileWorldLights();
493         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
494         {
495                 if (r_shadow_program_light[i])
496                 {
497                         GL_Backend_FreeProgram(r_shadow_program_light[i]);
498                         r_shadow_program_light[i] = 0;
499                 }
500         }
501         numcubemaps = 0;
502         r_shadow_attenuation2dtexture = NULL;
503         r_shadow_attenuation3dtexture = NULL;
504         R_FreeTexturePool(&r_shadow_texturepool);
505         R_FreeTexturePool(&r_shadow_filters_texturepool);
506         maxshadowelements = 0;
507         if (shadowelements)
508                 Mem_Free(shadowelements);
509         shadowelements = NULL;
510         maxvertexupdate = 0;
511         if (vertexupdate)
512                 Mem_Free(vertexupdate);
513         vertexupdate = NULL;
514         if (vertexremap)
515                 Mem_Free(vertexremap);
516         vertexremap = NULL;
517         vertexupdatenum = 0;
518         maxshadowmark = 0;
519         numshadowmark = 0;
520         if (shadowmark)
521                 Mem_Free(shadowmark);
522         shadowmark = NULL;
523         if (shadowmarklist)
524                 Mem_Free(shadowmarklist);
525         shadowmarklist = NULL;
526         shadowmarkcount = 0;
527         r_shadow_buffer_numleafpvsbytes = 0;
528         if (r_shadow_buffer_leafpvs)
529                 Mem_Free(r_shadow_buffer_leafpvs);
530         r_shadow_buffer_leafpvs = NULL;
531         if (r_shadow_buffer_leaflist)
532                 Mem_Free(r_shadow_buffer_leaflist);
533         r_shadow_buffer_leaflist = NULL;
534         r_shadow_buffer_numsurfacepvsbytes = 0;
535         if (r_shadow_buffer_surfacepvs)
536                 Mem_Free(r_shadow_buffer_surfacepvs);
537         r_shadow_buffer_surfacepvs = NULL;
538         if (r_shadow_buffer_surfacelist)
539                 Mem_Free(r_shadow_buffer_surfacelist);
540         r_shadow_buffer_surfacelist = NULL;
541 }
542
543 void r_shadow_newmap(void)
544 {
545 }
546
547 void R_Shadow_Help_f(void)
548 {
549         Con_Printf(
550 "Documentation on r_shadow system:\n"
551 "Settings:\n"
552 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
553 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
554 "r_shadow_debuglight : render only this light number (-1 = all)\n"
555 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
556 "r_shadow_gloss2intensity : brightness of forced gloss\n"
557 "r_shadow_glossintensity : brightness of textured gloss\n"
558 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
559 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
560 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
561 "r_shadow_portallight : use portal visibility for static light precomputation\n"
562 "r_shadow_projectdistance : shadow volume projection distance\n"
563 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
564 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
565 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
566 "r_shadow_realtime_world : use high quality world lighting mode\n"
567 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
568 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
569 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
570 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
571 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
572 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
573 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
574 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
575 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
576 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
577 "r_shadow_scissor : use scissor optimization\n"
578 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
579 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
580 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
581 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
582 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
583 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
584 "Commands:\n"
585 "r_shadow_help : this help\n"
586         );
587 }
588
589 void R_Shadow_Init(void)
590 {
591         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
592         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
593         Cvar_RegisterVariable(&r_shadow_debuglight);
594         Cvar_RegisterVariable(&r_shadow_gloss);
595         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
596         Cvar_RegisterVariable(&r_shadow_glossintensity);
597         Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
598         Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
599         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
600         Cvar_RegisterVariable(&r_shadow_portallight);
601         Cvar_RegisterVariable(&r_shadow_projectdistance);
602         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
603         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
604         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
605         Cvar_RegisterVariable(&r_shadow_realtime_world);
606         Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
607         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
608         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
609         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
610         Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
611         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
612         Cvar_RegisterVariable(&r_shadow_scissor);
613         Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
614         Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
615         Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
616         Cvar_RegisterVariable(&r_shadow_texture3d);
617         Cvar_RegisterVariable(&r_shadow_visiblelighting);
618         Cvar_RegisterVariable(&r_shadow_visiblevolumes);
619         Cvar_RegisterVariable(&r_shadow_glsl);
620         Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
621         Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
622         Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
623         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
624         if (gamemode == GAME_TENEBRAE)
625         {
626                 Cvar_SetValue("r_shadow_gloss", 2);
627                 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
628         }
629         Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
630         R_Shadow_EditLights_Init();
631         r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
632         r_shadow_worldlightchain = NULL;
633         maxshadowelements = 0;
634         shadowelements = NULL;
635         maxvertexupdate = 0;
636         vertexupdate = NULL;
637         vertexremap = NULL;
638         vertexupdatenum = 0;
639         maxshadowmark = 0;
640         numshadowmark = 0;
641         shadowmark = NULL;
642         shadowmarklist = NULL;
643         shadowmarkcount = 0;
644         r_shadow_buffer_numleafpvsbytes = 0;
645         r_shadow_buffer_leafpvs = NULL;
646         r_shadow_buffer_leaflist = NULL;
647         r_shadow_buffer_numsurfacepvsbytes = 0;
648         r_shadow_buffer_surfacepvs = NULL;
649         r_shadow_buffer_surfacelist = NULL;
650         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
651 }
652
653 static matrix4x4_t matrix_attenuationxyz =
654 {
655         {
656                 {0.5, 0.0, 0.0, 0.5},
657                 {0.0, 0.5, 0.0, 0.5},
658                 {0.0, 0.0, 0.5, 0.5},
659                 {0.0, 0.0, 0.0, 1.0}
660         }
661 };
662
663 static matrix4x4_t matrix_attenuationz =
664 {
665         {
666                 {0.0, 0.0, 0.5, 0.5},
667                 {0.0, 0.0, 0.0, 0.5},
668                 {0.0, 0.0, 0.0, 0.5},
669                 {0.0, 0.0, 0.0, 1.0}
670         }
671 };
672
673 int *R_Shadow_ResizeShadowElements(int numtris)
674 {
675         // make sure shadowelements is big enough for this volume
676         if (maxshadowelements < numtris * 24)
677         {
678                 maxshadowelements = numtris * 24;
679                 if (shadowelements)
680                         Mem_Free(shadowelements);
681                 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
682         }
683         return shadowelements;
684 }
685
686 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
687 {
688         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
689         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
690         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
691         {
692                 if (r_shadow_buffer_leafpvs)
693                         Mem_Free(r_shadow_buffer_leafpvs);
694                 if (r_shadow_buffer_leaflist)
695                         Mem_Free(r_shadow_buffer_leaflist);
696                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
697                 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
698                 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
699         }
700         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
701         {
702                 if (r_shadow_buffer_surfacepvs)
703                         Mem_Free(r_shadow_buffer_surfacepvs);
704                 if (r_shadow_buffer_surfacelist)
705                         Mem_Free(r_shadow_buffer_surfacelist);
706                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
707                 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
708                 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
709         }
710 }
711
712 void R_Shadow_PrepareShadowMark(int numtris)
713 {
714         // make sure shadowmark is big enough for this volume
715         if (maxshadowmark < numtris)
716         {
717                 maxshadowmark = numtris;
718                 if (shadowmark)
719                         Mem_Free(shadowmark);
720                 if (shadowmarklist)
721                         Mem_Free(shadowmarklist);
722                 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
723                 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
724                 shadowmarkcount = 0;
725         }
726         shadowmarkcount++;
727         // if shadowmarkcount wrapped we clear the array and adjust accordingly
728         if (shadowmarkcount == 0)
729         {
730                 shadowmarkcount = 1;
731                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
732         }
733         numshadowmark = 0;
734 }
735
736 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)
737 {
738         int i, j;
739         int outtriangles = 0, outvertices = 0;
740         const int *element;
741         const float *vertex;
742
743         if (maxvertexupdate < innumvertices)
744         {
745                 maxvertexupdate = innumvertices;
746                 if (vertexupdate)
747                         Mem_Free(vertexupdate);
748                 if (vertexremap)
749                         Mem_Free(vertexremap);
750                 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
751                 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
752                 vertexupdatenum = 0;
753         }
754         vertexupdatenum++;
755         if (vertexupdatenum == 0)
756         {
757                 vertexupdatenum = 1;
758                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
759                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
760         }
761
762         for (i = 0;i < numshadowmarktris;i++)
763                 shadowmark[shadowmarktris[i]] = shadowmarkcount;
764
765         for (i = 0;i < numshadowmarktris;i++)
766         {
767                 element = inelement3i + shadowmarktris[i] * 3;
768                 // make sure the vertices are created
769                 for (j = 0;j < 3;j++)
770                 {
771                         if (vertexupdate[element[j]] != vertexupdatenum)
772                         {
773                                 float ratio, direction[3];
774                                 vertexupdate[element[j]] = vertexupdatenum;
775                                 vertexremap[element[j]] = outvertices;
776                                 vertex = invertex3f + element[j] * 3;
777                                 // project one copy of the vertex to the sphere radius of the light
778                                 // (FIXME: would projecting it to the light box be better?)
779                                 VectorSubtract(vertex, projectorigin, direction);
780                                 ratio = projectdistance / VectorLength(direction);
781                                 VectorCopy(vertex, outvertex3f);
782                                 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
783                                 outvertex3f += 6;
784                                 outvertices += 2;
785                         }
786                 }
787         }
788
789         for (i = 0;i < numshadowmarktris;i++)
790         {
791                 int remappedelement[3];
792                 int markindex;
793                 const int *neighbortriangle;
794
795                 markindex = shadowmarktris[i] * 3;
796                 element = inelement3i + markindex;
797                 neighbortriangle = inneighbor3i + markindex;
798                 // output the front and back triangles
799                 outelement3i[0] = vertexremap[element[0]];
800                 outelement3i[1] = vertexremap[element[1]];
801                 outelement3i[2] = vertexremap[element[2]];
802                 outelement3i[3] = vertexremap[element[2]] + 1;
803                 outelement3i[4] = vertexremap[element[1]] + 1;
804                 outelement3i[5] = vertexremap[element[0]] + 1;
805
806                 outelement3i += 6;
807                 outtriangles += 2;
808                 // output the sides (facing outward from this triangle)
809                 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
810                 {
811                         remappedelement[0] = vertexremap[element[0]];
812                         remappedelement[1] = vertexremap[element[1]];
813                         outelement3i[0] = remappedelement[1];
814                         outelement3i[1] = remappedelement[0];
815                         outelement3i[2] = remappedelement[0] + 1;
816                         outelement3i[3] = remappedelement[1];
817                         outelement3i[4] = remappedelement[0] + 1;
818                         outelement3i[5] = remappedelement[1] + 1;
819
820                         outelement3i += 6;
821                         outtriangles += 2;
822                 }
823                 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
824                 {
825                         remappedelement[1] = vertexremap[element[1]];
826                         remappedelement[2] = vertexremap[element[2]];
827                         outelement3i[0] = remappedelement[2];
828                         outelement3i[1] = remappedelement[1];
829                         outelement3i[2] = remappedelement[1] + 1;
830                         outelement3i[3] = remappedelement[2];
831                         outelement3i[4] = remappedelement[1] + 1;
832                         outelement3i[5] = remappedelement[2] + 1;
833
834                         outelement3i += 6;
835                         outtriangles += 2;
836                 }
837                 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
838                 {
839                         remappedelement[0] = vertexremap[element[0]];
840                         remappedelement[2] = vertexremap[element[2]];
841                         outelement3i[0] = remappedelement[0];
842                         outelement3i[1] = remappedelement[2];
843                         outelement3i[2] = remappedelement[2] + 1;
844                         outelement3i[3] = remappedelement[0];
845                         outelement3i[4] = remappedelement[2] + 1;
846                         outelement3i[5] = remappedelement[0] + 1;
847
848                         outelement3i += 6;
849                         outtriangles += 2;
850                 }
851         }
852         if (outnumvertices)
853                 *outnumvertices = outvertices;
854         return outtriangles;
855 }
856
857 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)
858 {
859         int tris, outverts;
860         if (projectdistance < 0.1)
861         {
862                 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
863                 return;
864         }
865         if (!numverts || !nummarktris)
866                 return;
867         // make sure shadowelements is big enough for this volume
868         if (maxshadowelements < nummarktris * 24)
869                 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
870         tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
871         R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
872 }
873
874 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)
875 {
876         int t, tend;
877         const int *e;
878         const float *v[3];
879         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
880                 return;
881         tend = firsttriangle + numtris;
882         if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
883          && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
884          && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
885         {
886                 // surface box entirely inside light box, no box cull
887                 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
888                         if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
889                                 shadowmarklist[numshadowmark++] = t;
890         }
891         else
892         {
893                 // surface box not entirely inside light box, cull each triangle
894                 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
895                 {
896                         v[0] = invertex3f + e[0] * 3;
897                         v[1] = invertex3f + e[1] * 3;
898                         v[2] = invertex3f + e[2] * 3;
899                         if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
900                          && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
901                          && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
902                          && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
903                          && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
904                          && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
905                          && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
906                                 shadowmarklist[numshadowmark++] = t;
907                 }
908         }
909 }
910
911 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
912 {
913         rmeshstate_t m;
914         if (r_shadow_compilingrtlight)
915         {
916                 // if we're compiling an rtlight, capture the mesh
917                 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
918                 return;
919         }
920         memset(&m, 0, sizeof(m));
921         m.pointer_vertex = vertex3f;
922         R_Mesh_State(&m);
923         GL_LockArrays(0, numvertices);
924         if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
925         {
926                 // increment stencil if backface is behind depthbuffer
927                 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
928                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
929                 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
930                 c_rt_shadowmeshes++;
931                 c_rt_shadowtris += numtriangles;
932                 // decrement stencil if frontface is behind depthbuffer
933                 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
934                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
935         }
936         R_Mesh_Draw(0, numvertices, numtriangles, element3i);
937         c_rt_shadowmeshes++;
938         c_rt_shadowtris += numtriangles;
939         GL_LockArrays(0, 0);
940 }
941
942 static void R_Shadow_MakeTextures(void)
943 {
944         int x, y, z, d;
945         float v[3], intensity;
946         qbyte *data;
947         R_FreeTexturePool(&r_shadow_texturepool);
948         r_shadow_texturepool = R_AllocTexturePool();
949         r_shadow_attenpower = r_shadow_lightattenuationpower.value;
950         r_shadow_attenscale = r_shadow_lightattenuationscale.value;
951 #define ATTEN2DSIZE 64
952 #define ATTEN3DSIZE 32
953         data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
954         for (y = 0;y < ATTEN2DSIZE;y++)
955         {
956                 for (x = 0;x < ATTEN2DSIZE;x++)
957                 {
958                         v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
959                         v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
960                         v[2] = 0;
961                         intensity = 1.0f - sqrt(DotProduct(v, v));
962                         if (intensity > 0)
963                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
964                         d = bound(0, intensity, 255);
965                         data[(y*ATTEN2DSIZE+x)*4+0] = d;
966                         data[(y*ATTEN2DSIZE+x)*4+1] = d;
967                         data[(y*ATTEN2DSIZE+x)*4+2] = d;
968                         data[(y*ATTEN2DSIZE+x)*4+3] = d;
969                 }
970         }
971         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
972         if (r_shadow_texture3d.integer)
973         {
974                 for (z = 0;z < ATTEN3DSIZE;z++)
975                 {
976                         for (y = 0;y < ATTEN3DSIZE;y++)
977                         {
978                                 for (x = 0;x < ATTEN3DSIZE;x++)
979                                 {
980                                         v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
981                                         v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
982                                         v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
983                                         intensity = 1.0f - sqrt(DotProduct(v, v));
984                                         if (intensity > 0)
985                                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
986                                         d = bound(0, intensity, 255);
987                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
988                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
989                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
990                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
991                                 }
992                         }
993                 }
994                 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
995         }
996         Mem_Free(data);
997 }
998
999 void R_Shadow_ValidateCvars(void)
1000 {
1001         if (r_shadow_texture3d.integer && !gl_texture3d)
1002                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1003         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1004                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1005 }
1006
1007 // light currently being rendered
1008 static rtlight_t *r_shadow_rtlight;
1009 // light filter cubemap being used by the light
1010 static rtexture_t *r_shadow_lightcubemap;
1011
1012 // this is the location of the eye in entity space
1013 static vec3_t r_shadow_entityeyeorigin;
1014 // this is the location of the light in entity space
1015 static vec3_t r_shadow_entitylightorigin;
1016 // this transforms entity coordinates to light filter cubemap coordinates
1017 // (also often used for other purposes)
1018 static matrix4x4_t r_shadow_entitytolight;
1019 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1020 // of attenuation texturing in full 3D (Z result often ignored)
1021 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1022 // this transforms only the Z to S, and T is always 0.5
1023 static matrix4x4_t r_shadow_entitytoattenuationz;
1024 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1025 static vec3_t r_shadow_entitylightcolor;
1026
1027 static int r_shadow_lightpermutation;
1028 static int r_shadow_lightprog;
1029
1030 void R_Shadow_Stage_Begin(void)
1031 {
1032         rmeshstate_t m;
1033
1034         R_Shadow_ValidateCvars();
1035
1036         if (!r_shadow_attenuation2dtexture
1037          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1038          || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1039          || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1040                 R_Shadow_MakeTextures();
1041
1042         memset(&m, 0, sizeof(m));
1043         GL_BlendFunc(GL_ONE, GL_ZERO);
1044         GL_DepthMask(false);
1045         GL_DepthTest(true);
1046         R_Mesh_State(&m);
1047         GL_Color(0, 0, 0, 1);
1048         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1049         qglEnable(GL_CULL_FACE);
1050         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1051         r_shadowstage = R_SHADOWSTAGE_NONE;
1052 }
1053
1054 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1055 {
1056         r_shadow_rtlight = rtlight;
1057 }
1058
1059 void R_Shadow_Stage_Reset(void)
1060 {
1061         rmeshstate_t m;
1062         if (gl_support_stenciltwoside)
1063                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1064         if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1065         {
1066                 qglUseProgramObjectARB(0);
1067                 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1068                 qglBegin(GL_TRIANGLES);
1069                 qglEnd();
1070                 CHECKGLERROR
1071         }
1072         memset(&m, 0, sizeof(m));
1073         R_Mesh_State(&m);
1074 }
1075
1076 void R_Shadow_Stage_StencilShadowVolumes(void)
1077 {
1078         R_Shadow_Stage_Reset();
1079         GL_Color(1, 1, 1, 1);
1080         GL_ColorMask(0, 0, 0, 0);
1081         GL_BlendFunc(GL_ONE, GL_ZERO);
1082         GL_DepthMask(false);
1083         GL_DepthTest(true);
1084         qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1085         //if (r_shadow_shadow_polygonoffset.value != 0)
1086         //{
1087         //      qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1088         //      qglEnable(GL_POLYGON_OFFSET_FILL);
1089         //}
1090         //else
1091         //      qglDisable(GL_POLYGON_OFFSET_FILL);
1092         qglDepthFunc(GL_GEQUAL);
1093         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1094         qglEnable(GL_STENCIL_TEST);
1095         qglStencilFunc(GL_ALWAYS, 128, ~0);
1096         if (gl_ext_stenciltwoside.integer)
1097         {
1098                 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1099                 qglDisable(GL_CULL_FACE);
1100                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1101                 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1102                 qglStencilMask(~0);
1103                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
1104                 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1105                 qglStencilMask(~0);
1106                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1107         }
1108         else
1109         {
1110                 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1111                 qglEnable(GL_CULL_FACE);
1112                 qglStencilMask(~0);
1113                 // this is changed by every shadow render so its value here is unimportant
1114                 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1115         }
1116         GL_Clear(GL_STENCIL_BUFFER_BIT);
1117         c_rt_clears++;
1118 }
1119
1120 void R_Shadow_Stage_Lighting(int stenciltest)
1121 {
1122         rmeshstate_t m;
1123         R_Shadow_Stage_Reset();
1124         GL_BlendFunc(GL_ONE, GL_ONE);
1125         GL_DepthMask(false);
1126         GL_DepthTest(true);
1127         qglPolygonOffset(0, 0);
1128         //qglDisable(GL_POLYGON_OFFSET_FILL);
1129         GL_Color(1, 1, 1, 1);
1130         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1131         qglDepthFunc(GL_EQUAL);
1132         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1133         qglEnable(GL_CULL_FACE);
1134         if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1135                 qglEnable(GL_STENCIL_TEST);
1136         else
1137                 qglDisable(GL_STENCIL_TEST);
1138         qglStencilMask(~0);
1139         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1140         // only draw light where this geometry was already rendered AND the
1141         // stencil is 128 (values other than this mean shadow)
1142         qglStencilFunc(GL_EQUAL, 128, ~0);
1143         if (r_shadow_glsl.integer && r_shadow_program_light[0])
1144         {
1145                 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1146                 memset(&m, 0, sizeof(m));
1147                 m.pointer_vertex = varray_vertex3f;
1148                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1149                 m.pointer_texcoord3f[1] = varray_svector3f;
1150                 m.pointer_texcoord3f[2] = varray_tvector3f;
1151                 m.pointer_texcoord3f[3] = varray_normal3f;
1152                 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1153                 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1154                 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1155                 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1156                 // TODO: support fog (after renderer is converted to texture fog)
1157                 m.tex[4] = R_GetTexture(r_texture_white); // fog
1158                 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1159                 R_Mesh_State(&m);
1160                 GL_BlendFunc(GL_ONE, GL_ONE);
1161                 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1162                 CHECKGLERROR
1163                 r_shadow_lightpermutation = 0;
1164                 // only add a feature to the permutation if that permutation exists
1165                 // (otherwise it might end up not using a shader at all, which looks
1166                 // worse than using less features)
1167                 if (r_shadow_rtlight->specularscale && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1168                         r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1169                 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1170                 //      r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1171                 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1172                         r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1173                 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1174                         r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1175                 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1176                 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1177                 // TODO: support fog (after renderer is converted to texture fog)
1178                 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1179                 {
1180                         qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1181                 }
1182                 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1183                 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1184                 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1185                 {
1186                         qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1187                         qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1188                 }
1189                 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1190                 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1191                 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1192                 //{
1193                 //      qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1194                 //}
1195                 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1196                 {
1197                         qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1198                         qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1199                 }
1200         }
1201         else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1202                 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1203         else
1204                 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1205 }
1206
1207 void R_Shadow_Stage_VisibleShadowVolumes(void)
1208 {
1209         R_Shadow_Stage_Reset();
1210         GL_BlendFunc(GL_ONE, GL_ONE);
1211         GL_DepthMask(false);
1212         GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1213         qglPolygonOffset(0, 0);
1214         GL_Color(0.0, 0.0125, 0.1, 1);
1215         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1216         qglDepthFunc(GL_GEQUAL);
1217         qglCullFace(GL_FRONT); // this culls back
1218         qglDisable(GL_CULL_FACE);
1219         qglDisable(GL_STENCIL_TEST);
1220         r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1221 }
1222
1223 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1224 {
1225         R_Shadow_Stage_Reset();
1226         GL_BlendFunc(GL_ONE, GL_ONE);
1227         GL_DepthMask(false);
1228         GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1229         qglPolygonOffset(0, 0);
1230         GL_Color(0.1, 0.0125, 0, 1);
1231         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1232         qglDepthFunc(GL_EQUAL);
1233         qglCullFace(GL_FRONT); // this culls back
1234         qglEnable(GL_CULL_FACE);
1235         if (stenciltest)
1236                 qglEnable(GL_STENCIL_TEST);
1237         else
1238                 qglDisable(GL_STENCIL_TEST);
1239         r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1240 }
1241
1242 void R_Shadow_Stage_End(void)
1243 {
1244         R_Shadow_Stage_Reset();
1245         R_Shadow_Stage_ActiveLight(NULL);
1246         GL_BlendFunc(GL_ONE, GL_ZERO);
1247         GL_DepthMask(true);
1248         GL_DepthTest(true);
1249         qglPolygonOffset(0, 0);
1250         //qglDisable(GL_POLYGON_OFFSET_FILL);
1251         GL_Color(1, 1, 1, 1);
1252         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1253         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1254         qglDepthFunc(GL_LEQUAL);
1255         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1256         qglDisable(GL_STENCIL_TEST);
1257         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1258         if (gl_support_stenciltwoside)
1259                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1260         qglStencilMask(~0);
1261         qglStencilFunc(GL_ALWAYS, 128, ~0);
1262         r_shadowstage = R_SHADOWSTAGE_NONE;
1263 }
1264
1265 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1266 {
1267         int i, ix1, iy1, ix2, iy2;
1268         float x1, y1, x2, y2;
1269         vec4_t v, v2;
1270         rmesh_t mesh;
1271         mplane_t planes[11];
1272         float vertex3f[256*3];
1273
1274         // if view is inside the light box, just say yes it's visible
1275         if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1276         {
1277                 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1278                 return false;
1279         }
1280
1281         // create a temporary brush describing the area the light can affect in worldspace
1282         VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1283         VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1284         VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1285         VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1286         VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1287         VectorSet   (planes[ 5].normal,  1, 0, 0);         planes[ 5].dist =  maxs[0];
1288         VectorSet   (planes[ 6].normal, -1, 0, 0);         planes[ 6].dist = -mins[0];
1289         VectorSet   (planes[ 7].normal, 0,  1, 0);         planes[ 7].dist =  maxs[1];
1290         VectorSet   (planes[ 8].normal, 0, -1, 0);         planes[ 8].dist = -mins[1];
1291         VectorSet   (planes[ 9].normal, 0, 0,  1);         planes[ 9].dist =  maxs[2];
1292         VectorSet   (planes[10].normal, 0, 0, -1);         planes[10].dist = -mins[2];
1293
1294         // turn the brush into a mesh
1295         memset(&mesh, 0, sizeof(rmesh_t));
1296         mesh.maxvertices = 256;
1297         mesh.vertex3f = vertex3f;
1298         mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1299         R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1300
1301         // if that mesh is empty, the light is not visible at all
1302         if (!mesh.numvertices)
1303                 return true;
1304
1305         if (!r_shadow_scissor.integer)
1306                 return false;
1307
1308         // if that mesh is not empty, check what area of the screen it covers
1309         x1 = y1 = x2 = y2 = 0;
1310         v[3] = 1.0f;
1311         for (i = 0;i < mesh.numvertices;i++)
1312         {
1313                 VectorCopy(mesh.vertex3f + i * 3, v);
1314                 GL_TransformToScreen(v, v2);
1315                 //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]);
1316                 if (i)
1317                 {
1318                         if (x1 > v2[0]) x1 = v2[0];
1319                         if (x2 < v2[0]) x2 = v2[0];
1320                         if (y1 > v2[1]) y1 = v2[1];
1321                         if (y2 < v2[1]) y2 = v2[1];
1322                 }
1323                 else
1324                 {
1325                         x1 = x2 = v2[0];
1326                         y1 = y2 = v2[1];
1327                 }
1328         }
1329
1330         // now convert the scissor rectangle to integer screen coordinates
1331         ix1 = x1 - 1.0f;
1332         iy1 = y1 - 1.0f;
1333         ix2 = x2 + 1.0f;
1334         iy2 = y2 + 1.0f;
1335         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1336
1337         // clamp it to the screen
1338         if (ix1 < r_view_x) ix1 = r_view_x;
1339         if (iy1 < r_view_y) iy1 = r_view_y;
1340         if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1341         if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1342
1343         // if it is inside out, it's not visible
1344         if (ix2 <= ix1 || iy2 <= iy1)
1345                 return true;
1346
1347         // the light area is visible, set up the scissor rectangle
1348         GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1349         //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1350         //qglEnable(GL_SCISSOR_TEST);
1351         c_rt_scissored++;
1352         return false;
1353 }
1354
1355 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1356 {
1357         float *color4f = varray_color4f;
1358         float dist, dot, intensity, v[3], n[3];
1359         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1360         {
1361                 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1362                 if ((dist = DotProduct(v, v)) < 1)
1363                 {
1364                         Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1365                         if ((dot = DotProduct(n, v)) > 0)
1366                         {
1367                                 dist = sqrt(dist);
1368                                 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1369                                 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1370                                 VectorScale(lightcolor, intensity, color4f);
1371                                 color4f[3] = 1;
1372                         }
1373                         else
1374                         {
1375                                 VectorClear(color4f);
1376                                 color4f[3] = 1;
1377                         }
1378                 }
1379                 else
1380                 {
1381                         VectorClear(color4f);
1382                         color4f[3] = 1;
1383                 }
1384         }
1385 }
1386
1387 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1388 {
1389         float *color4f = varray_color4f;
1390         float dist, dot, intensity, v[3], n[3];
1391         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1392         {
1393                 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1394                 if ((dist = fabs(v[2])) < 1)
1395                 {
1396                         Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1397                         if ((dot = DotProduct(n, v)) > 0)
1398                         {
1399                                 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1400                                 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1401                                 VectorScale(lightcolor, intensity, color4f);
1402                                 color4f[3] = 1;
1403                         }
1404                         else
1405                         {
1406                                 VectorClear(color4f);
1407                                 color4f[3] = 1;
1408                         }
1409                 }
1410                 else
1411                 {
1412                         VectorClear(color4f);
1413                         color4f[3] = 1;
1414                 }
1415         }
1416 }
1417
1418 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1419 {
1420         float *color4f = varray_color4f;
1421         float dot, intensity, v[3], n[3];
1422         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1423         {
1424                 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1425                 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1426                 if ((dot = DotProduct(n, v)) > 0)
1427                 {
1428                         intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1429                         VectorScale(lightcolor, intensity, color4f);
1430                         color4f[3] = 1;
1431                 }
1432                 else
1433                 {
1434                         VectorClear(color4f);
1435                         color4f[3] = 1;
1436                 }
1437         }
1438 }
1439
1440 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1441 {
1442         float *color4f = varray_color4f;
1443         float dist, intensity, v[3];
1444         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1445         {
1446                 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1447                 if ((dist = DotProduct(v, v)) < 1)
1448                 {
1449                         dist = sqrt(dist);
1450                         intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1451                         VectorScale(lightcolor, intensity, color4f);
1452                         color4f[3] = 1;
1453                 }
1454                 else
1455                 {
1456                         VectorClear(color4f);
1457                         color4f[3] = 1;
1458                 }
1459         }
1460 }
1461
1462 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1463 {
1464         float *color4f = varray_color4f;
1465         float dist, intensity, v[3];
1466         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1467         {
1468                 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1469                 if ((dist = fabs(v[2])) < 1)
1470                 {
1471                         intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1472                         VectorScale(lightcolor, intensity, color4f);
1473                         color4f[3] = 1;
1474                 }
1475                 else
1476                 {
1477                         VectorClear(color4f);
1478                         color4f[3] = 1;
1479                 }
1480         }
1481 }
1482
1483 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1484 #define USETEXMATRIX
1485
1486 #ifndef USETEXMATRIX
1487 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1488 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1489 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1490 {
1491         do
1492         {
1493                 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1494                 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1495                 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1496                 vertex3f += 3;
1497                 tc3f += 3;
1498         }
1499         while (--numverts);
1500 }
1501
1502 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1503 {
1504         do
1505         {
1506                 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1507                 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1508                 vertex3f += 3;
1509                 tc2f += 2;
1510         }
1511         while (--numverts);
1512 }
1513 #endif
1514
1515 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)
1516 {
1517         int i;
1518         float lightdir[3];
1519         for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1520         {
1521                 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1522                 // the cubemap normalizes this for us
1523                 out3f[0] = DotProduct(svector3f, lightdir);
1524                 out3f[1] = DotProduct(tvector3f, lightdir);
1525                 out3f[2] = DotProduct(normal3f, lightdir);
1526         }
1527 }
1528
1529 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)
1530 {
1531         int i;
1532         float lightdir[3], eyedir[3], halfdir[3];
1533         for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1534         {
1535                 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1536                 VectorNormalizeFast(lightdir);
1537                 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1538                 VectorNormalizeFast(eyedir);
1539                 VectorAdd(lightdir, eyedir, halfdir);
1540                 // the cubemap normalizes this for us
1541                 out3f[0] = DotProduct(svector3f, halfdir);
1542                 out3f[1] = DotProduct(tvector3f, halfdir);
1543                 out3f[2] = DotProduct(normal3f, halfdir);
1544         }
1545 }
1546
1547 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture)
1548 {
1549         int renders;
1550         float color[3], color2[3], colorscale, specularscale;
1551         rmeshstate_t m;
1552         // FIXME: support EF_NODEPTHTEST
1553         if (!basetexture)
1554                 basetexture = r_texture_white;
1555         if (!bumptexture)
1556                 bumptexture = r_texture_blanknormalmap;
1557         if (!pantstexture)
1558                 lightcolorpants = vec3_origin;
1559         if (!shirttexture)
1560                 lightcolorshirt = vec3_origin;
1561         if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1562                 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
1563         else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1564         {
1565                 glosstexture = r_texture_white;
1566                 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
1567         }
1568         else
1569         {
1570                 glosstexture = r_texture_black;
1571                 specularscale = 0;
1572         }
1573         if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1574                 return;
1575         if (r_shadowstage == R_SHADOWSTAGE_VISIBLELIGHTING)
1576         {
1577                 int passes = 0;
1578                 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1579                         passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1580                 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1581                 {
1582                         // TODO: add direct pants/shirt rendering
1583                         if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1584                                 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1585                         if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1586                                 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1587                         if (r_shadow_rtlight->ambientscale)
1588                         {
1589                                 colorscale = r_shadow_rtlight->ambientscale;
1590                                 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1591                                 {
1592                                 }
1593                                 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1594                                 {
1595                                 }
1596                                 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1597                                 {
1598                                 }
1599                                 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1600                                 {
1601                                 }
1602                                 else
1603                                         passes++;
1604                                 VectorScale(lightcolorbase, colorscale, color2);
1605                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1606                                         passes++;
1607                         }
1608                         if (r_shadow_rtlight->diffusescale)
1609                         {
1610                                 colorscale = r_shadow_rtlight->diffusescale;
1611                                 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1612                                 {
1613                                         // 3/2 3D combine path (Geforce3, Radeon 8500)
1614                                         passes++;
1615                                 }
1616                                 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1617                                 {
1618                                         // 1/2/2 3D combine path (original Radeon)
1619                                         passes += 2;
1620                                 }
1621                                 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1622                                 {
1623                                         // 2/2 3D combine path (original Radeon)
1624                                         passes++;
1625                                 }
1626                                 else if (r_textureunits.integer >= 4)
1627                                 {
1628                                         // 4/2 2D combine path (Geforce3, Radeon 8500)
1629                                         passes++;
1630                                 }
1631                                 else
1632                                 {
1633                                         // 2/2/2 2D combine path (any dot3 card)
1634                                         passes += 2;
1635                                 }
1636                                 VectorScale(lightcolorbase, colorscale, color2);
1637                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1638                                         passes++;
1639                         }
1640                         if (specularscale && glosstexture != r_texture_black)
1641                         {
1642                                 //if (gl_support_blendsquare)
1643                                 {
1644                                         colorscale = specularscale;
1645                                         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1646                                                 passes += 4;
1647                                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1648                                                 passes += 3;
1649                                         else
1650                                                 passes += 4;
1651                                         VectorScale(lightcolorbase, colorscale, color2);
1652                                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1653                                                 passes++;
1654                                 }
1655                         }
1656                 }
1657                 else
1658                 {
1659                         // TODO: add direct pants/shirt rendering
1660                         if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1661                                 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1662                         if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1663                                 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1664                         if (r_shadow_rtlight->ambientscale)
1665                         {
1666                                 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
1667                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1668                                         passes++;
1669                         }
1670                         if (r_shadow_rtlight->diffusescale)
1671                         {
1672                                 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
1673                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1674                                         passes++;
1675                         }
1676                 }
1677                 if (passes)
1678                 {
1679                         GL_Color(0.1*passes, 0.025*passes, 0, 1);
1680                         memset(&m, 0, sizeof(m));
1681                         m.pointer_vertex = vertex3f;
1682                         R_Mesh_State(&m);
1683                         GL_LockArrays(firstvertex, numvertices);
1684                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1685                         GL_LockArrays(0, 0);
1686                 }
1687                 return;
1688         }
1689         else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1690         {
1691                 // GLSL shader path (GFFX5200, Radeon 9500)
1692                 R_Mesh_VertexPointer(vertex3f);
1693                 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1694                 R_Mesh_TexCoordPointer(1, 3, svector3f);
1695                 R_Mesh_TexCoordPointer(2, 3, tvector3f);
1696                 R_Mesh_TexCoordPointer(3, 3, normal3f);
1697                 R_Mesh_TexBind(0, R_GetTexture(bumptexture));
1698                 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1699                 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1700                 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1701                 {
1702                         qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1703                 }
1704                 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1705                 GL_LockArrays(firstvertex, numvertices);
1706                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1707                 c_rt_lightmeshes++;
1708                 c_rt_lighttris += numtriangles;
1709                 // TODO: add direct pants/shirt rendering
1710                 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1711                 {
1712                         R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1713                         qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1714                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1715                         c_rt_lightmeshes++;
1716                         c_rt_lighttris += numtriangles;
1717                 }
1718                 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1719                 {
1720                         R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1721                         qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1722                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1723                         c_rt_lightmeshes++;
1724                         c_rt_lighttris += numtriangles;
1725                 }
1726                 GL_LockArrays(0, 0);
1727         }
1728         else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
1729         {
1730                 // TODO: add direct pants/shirt rendering
1731                 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1732                         R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1733                 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1734                         R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1735                 if (r_shadow_rtlight->ambientscale)
1736                 {
1737                         GL_Color(1,1,1,1);
1738                         colorscale = r_shadow_rtlight->ambientscale;
1739                         // colorscale accounts for how much we multiply the brightness
1740                         // during combine.
1741                         //
1742                         // mult is how many times the final pass of the lighting will be
1743                         // performed to get more brightness than otherwise possible.
1744                         //
1745                         // Limit mult to 64 for sanity sake.
1746                         if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1747                         {
1748                                 // 3 3D combine path (Geforce3, Radeon 8500)
1749                                 memset(&m, 0, sizeof(m));
1750                                 m.pointer_vertex = vertex3f;
1751                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1752 #ifdef USETEXMATRIX
1753                                 m.pointer_texcoord3f[0] = vertex3f;
1754                                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1755 #else
1756                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1757                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1758 #endif
1759                                 m.tex[1] = R_GetTexture(basetexture);
1760                                 m.pointer_texcoord[1] = texcoord2f;
1761                                 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1762 #ifdef USETEXMATRIX
1763                                 m.pointer_texcoord3f[2] = vertex3f;
1764                                 m.texmatrix[2] = r_shadow_entitytolight;
1765 #else
1766                                 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1767                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1768 #endif
1769                                 GL_BlendFunc(GL_ONE, GL_ONE);
1770                         }
1771                         else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1772                         {
1773                                 // 2 3D combine path (Geforce3, original Radeon)
1774                                 memset(&m, 0, sizeof(m));
1775                                 m.pointer_vertex = vertex3f;
1776                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1777 #ifdef USETEXMATRIX
1778                                 m.pointer_texcoord3f[0] = vertex3f;
1779                                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1780 #else
1781                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1782                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1783 #endif
1784                                 m.tex[1] = R_GetTexture(basetexture);
1785                                 m.pointer_texcoord[1] = texcoord2f;
1786                                 GL_BlendFunc(GL_ONE, GL_ONE);
1787                         }
1788                         else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1789                         {
1790                                 // 4 2D combine path (Geforce3, Radeon 8500)
1791                                 memset(&m, 0, sizeof(m));
1792                                 m.pointer_vertex = vertex3f;
1793                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1794 #ifdef USETEXMATRIX
1795                                 m.pointer_texcoord3f[0] = vertex3f;
1796                                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1797 #else
1798                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1799                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1800 #endif
1801                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1802 #ifdef USETEXMATRIX
1803                                 m.pointer_texcoord3f[1] = vertex3f;
1804                                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1805 #else
1806                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1807                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1808 #endif
1809                                 m.tex[2] = R_GetTexture(basetexture);
1810                                 m.pointer_texcoord[2] = texcoord2f;
1811                                 if (r_shadow_lightcubemap != r_texture_whitecube)
1812                                 {
1813                                         m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1814 #ifdef USETEXMATRIX
1815                                         m.pointer_texcoord3f[3] = vertex3f;
1816                                         m.texmatrix[3] = r_shadow_entitytolight;
1817 #else
1818                                         m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1819                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1820 #endif
1821                                 }
1822                                 GL_BlendFunc(GL_ONE, GL_ONE);
1823                         }
1824                         else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1825                         {
1826                                 // 3 2D combine path (Geforce3, original Radeon)
1827                                 memset(&m, 0, sizeof(m));
1828                                 m.pointer_vertex = vertex3f;
1829                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1830 #ifdef USETEXMATRIX
1831                                 m.pointer_texcoord3f[0] = vertex3f;
1832                                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1833 #else
1834                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1835                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1836 #endif
1837                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1838 #ifdef USETEXMATRIX
1839                                 m.pointer_texcoord3f[1] = vertex3f;
1840                                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1841 #else
1842                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1843                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1844 #endif
1845                                 m.tex[2] = R_GetTexture(basetexture);
1846                                 m.pointer_texcoord[2] = texcoord2f;
1847                                 GL_BlendFunc(GL_ONE, GL_ONE);
1848                         }
1849                         else
1850                         {
1851                                 // 2/2/2 2D combine path (any dot3 card)
1852                                 memset(&m, 0, sizeof(m));
1853                                 m.pointer_vertex = vertex3f;
1854                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1855 #ifdef USETEXMATRIX
1856                                 m.pointer_texcoord3f[0] = vertex3f;
1857                                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1858 #else
1859                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1860                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1861 #endif
1862                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1863 #ifdef USETEXMATRIX
1864                                 m.pointer_texcoord3f[1] = vertex3f;
1865                                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1866 #else
1867                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1868                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1869 #endif
1870                                 R_Mesh_State(&m);
1871                                 GL_ColorMask(0,0,0,1);
1872                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1873                                 GL_LockArrays(firstvertex, numvertices);
1874                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1875                                 GL_LockArrays(0, 0);
1876                                 c_rt_lightmeshes++;
1877                                 c_rt_lighttris += numtriangles;
1878
1879                                 memset(&m, 0, sizeof(m));
1880                                 m.pointer_vertex = vertex3f;
1881                                 m.tex[0] = R_GetTexture(basetexture);
1882                                 m.pointer_texcoord[0] = texcoord2f;
1883                                 if (r_shadow_lightcubemap != r_texture_whitecube)
1884                                 {
1885                                         m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1886 #ifdef USETEXMATRIX
1887                                         m.pointer_texcoord3f[1] = vertex3f;
1888                                         m.texmatrix[1] = r_shadow_entitytolight;
1889 #else
1890                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1891                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1892 #endif
1893                                 }
1894                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1895                         }
1896                         // this final code is shared
1897                         R_Mesh_State(&m);
1898                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1899                         VectorScale(lightcolorbase, colorscale, color2);
1900                         GL_LockArrays(firstvertex, numvertices);
1901                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1902                         {
1903                                 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1904                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1905                                 c_rt_lightmeshes++;
1906                                 c_rt_lighttris += numtriangles;
1907                         }
1908                         GL_LockArrays(0, 0);
1909                 }
1910                 if (r_shadow_rtlight->diffusescale)
1911                 {
1912                         GL_Color(1,1,1,1);
1913                         colorscale = r_shadow_rtlight->diffusescale;
1914                         // colorscale accounts for how much we multiply the brightness
1915                         // during combine.
1916                         //
1917                         // mult is how many times the final pass of the lighting will be
1918                         // performed to get more brightness than otherwise possible.
1919                         //
1920                         // Limit mult to 64 for sanity sake.
1921                         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1922                         {
1923                                 // 3/2 3D combine path (Geforce3, Radeon 8500)
1924                                 memset(&m, 0, sizeof(m));
1925                                 m.pointer_vertex = vertex3f;
1926                                 m.tex[0] = R_GetTexture(bumptexture);
1927                                 m.texcombinergb[0] = GL_REPLACE;
1928                                 m.pointer_texcoord[0] = texcoord2f;
1929                                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1930                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1931                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1932                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
1933                                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1934 #ifdef USETEXMATRIX
1935                                 m.pointer_texcoord3f[2] = vertex3f;
1936                                 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1937 #else
1938                                 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1939                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1940 #endif
1941                                 R_Mesh_State(&m);
1942                                 GL_ColorMask(0,0,0,1);
1943                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1944                                 GL_LockArrays(firstvertex, numvertices);
1945                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1946                                 GL_LockArrays(0, 0);
1947                                 c_rt_lightmeshes++;
1948                                 c_rt_lighttris += numtriangles;
1949
1950                                 memset(&m, 0, sizeof(m));
1951                                 m.pointer_vertex = vertex3f;
1952                                 m.tex[0] = R_GetTexture(basetexture);
1953                                 m.pointer_texcoord[0] = texcoord2f;
1954                                 if (r_shadow_lightcubemap != r_texture_whitecube)
1955                                 {
1956                                         m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1957 #ifdef USETEXMATRIX
1958                                         m.pointer_texcoord3f[1] = vertex3f;
1959                                         m.texmatrix[1] = r_shadow_entitytolight;
1960 #else
1961                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1962                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1963 #endif
1964                                 }
1965                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1966                         }
1967                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1968                         {
1969                                 // 1/2/2 3D combine path (original Radeon)
1970                                 memset(&m, 0, sizeof(m));
1971                                 m.pointer_vertex = vertex3f;
1972                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1973 #ifdef USETEXMATRIX
1974                                 m.pointer_texcoord3f[0] = vertex3f;
1975                                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1976 #else
1977                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1978                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1979 #endif
1980                                 R_Mesh_State(&m);
1981                                 GL_ColorMask(0,0,0,1);
1982                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1983                                 GL_LockArrays(firstvertex, numvertices);
1984                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1985                                 GL_LockArrays(0, 0);
1986                                 c_rt_lightmeshes++;
1987                                 c_rt_lighttris += numtriangles;
1988
1989                                 memset(&m, 0, sizeof(m));
1990                                 m.pointer_vertex = vertex3f;
1991                                 m.tex[0] = R_GetTexture(bumptexture);
1992                                 m.texcombinergb[0] = GL_REPLACE;
1993                                 m.pointer_texcoord[0] = texcoord2f;
1994                                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1995                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1996                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1997                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
1998                                 R_Mesh_State(&m);
1999                                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2000                                 GL_LockArrays(firstvertex, numvertices);
2001                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2002                                 GL_LockArrays(0, 0);
2003                                 c_rt_lightmeshes++;
2004                                 c_rt_lighttris += numtriangles;
2005
2006                                 memset(&m, 0, sizeof(m));
2007                                 m.pointer_vertex = vertex3f;
2008                                 m.tex[0] = R_GetTexture(basetexture);
2009                                 m.pointer_texcoord[0] = texcoord2f;
2010                                 if (r_shadow_lightcubemap != r_texture_whitecube)
2011                                 {
2012                                         m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2013 #ifdef USETEXMATRIX
2014                                         m.pointer_texcoord3f[1] = vertex3f;
2015                                         m.texmatrix[1] = r_shadow_entitytolight;
2016 #else
2017                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2018                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2019 #endif
2020                                 }
2021                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2022                         }
2023                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2024                         {
2025                                 // 2/2 3D combine path (original Radeon)
2026                                 memset(&m, 0, sizeof(m));
2027                                 m.pointer_vertex = vertex3f;
2028                                 m.tex[0] = R_GetTexture(bumptexture);
2029                                 m.texcombinergb[0] = GL_REPLACE;
2030                                 m.pointer_texcoord[0] = texcoord2f;
2031                                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2032                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2033                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2034                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2035                                 R_Mesh_State(&m);
2036                                 GL_ColorMask(0,0,0,1);
2037                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2038                                 GL_LockArrays(firstvertex, numvertices);
2039                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2040                                 GL_LockArrays(0, 0);
2041                                 c_rt_lightmeshes++;
2042                                 c_rt_lighttris += numtriangles;
2043
2044                                 memset(&m, 0, sizeof(m));
2045                                 m.pointer_vertex = vertex3f;
2046                                 m.tex[0] = R_GetTexture(basetexture);
2047                                 m.pointer_texcoord[0] = texcoord2f;
2048                                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2049 #ifdef USETEXMATRIX
2050                                 m.pointer_texcoord3f[1] = vertex3f;
2051                                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2052 #else
2053                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2054                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2055 #endif
2056                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2057                         }
2058                         else if (r_textureunits.integer >= 4)
2059                         {
2060                                 // 4/2 2D combine path (Geforce3, Radeon 8500)
2061                                 memset(&m, 0, sizeof(m));
2062                                 m.pointer_vertex = vertex3f;
2063                                 m.tex[0] = R_GetTexture(bumptexture);
2064                                 m.texcombinergb[0] = GL_REPLACE;
2065                                 m.pointer_texcoord[0] = texcoord2f;
2066                                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2067                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2068                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2069                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2070                                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2071 #ifdef USETEXMATRIX
2072                                 m.pointer_texcoord3f[2] = vertex3f;
2073                                 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2074 #else
2075                                 m.pointer_texcoord[2] = varray_texcoord2f[2];
2076                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2077 #endif
2078                                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2079 #ifdef USETEXMATRIX
2080                                 m.pointer_texcoord3f[3] = vertex3f;
2081                                 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2082 #else
2083                                 m.pointer_texcoord[3] = varray_texcoord2f[3];
2084                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2085 #endif
2086                                 R_Mesh_State(&m);
2087                                 GL_ColorMask(0,0,0,1);
2088                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2089                                 GL_LockArrays(firstvertex, numvertices);
2090                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2091                                 GL_LockArrays(0, 0);
2092                                 c_rt_lightmeshes++;
2093                                 c_rt_lighttris += numtriangles;
2094
2095                                 memset(&m, 0, sizeof(m));
2096                                 m.pointer_vertex = vertex3f;
2097                                 m.tex[0] = R_GetTexture(basetexture);
2098                                 m.pointer_texcoord[0] = texcoord2f;
2099                                 if (r_shadow_lightcubemap != r_texture_whitecube)
2100                                 {
2101                                         m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2102 #ifdef USETEXMATRIX
2103                                         m.pointer_texcoord3f[1] = vertex3f;
2104                                         m.texmatrix[1] = r_shadow_entitytolight;
2105 #else
2106                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2107                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2108 #endif
2109                                 }
2110                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2111                         }
2112                         else
2113                         {
2114                                 // 2/2/2 2D combine path (any dot3 card)
2115                                 memset(&m, 0, sizeof(m));
2116                                 m.pointer_vertex = vertex3f;
2117                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2118 #ifdef USETEXMATRIX
2119                                 m.pointer_texcoord3f[0] = vertex3f;
2120                                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2121 #else
2122                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
2123                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2124 #endif
2125                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2126 #ifdef USETEXMATRIX
2127                                 m.pointer_texcoord3f[1] = vertex3f;
2128                                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2129 #else
2130                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2131                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2132 #endif
2133                                 R_Mesh_State(&m);
2134                                 GL_ColorMask(0,0,0,1);
2135                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2136                                 GL_LockArrays(firstvertex, numvertices);
2137                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2138                                 GL_LockArrays(0, 0);
2139                                 c_rt_lightmeshes++;
2140                                 c_rt_lighttris += numtriangles;
2141
2142                                 memset(&m, 0, sizeof(m));
2143                                 m.pointer_vertex = vertex3f;
2144                                 m.tex[0] = R_GetTexture(bumptexture);
2145                                 m.texcombinergb[0] = GL_REPLACE;
2146                                 m.pointer_texcoord[0] = texcoord2f;
2147                                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2148                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2149                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2150                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2151                                 R_Mesh_State(&m);
2152                                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2153                                 GL_LockArrays(firstvertex, numvertices);
2154                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2155                                 GL_LockArrays(0, 0);
2156                                 c_rt_lightmeshes++;
2157                                 c_rt_lighttris += numtriangles;
2158
2159                                 memset(&m, 0, sizeof(m));
2160                                 m.pointer_vertex = vertex3f;
2161                                 m.tex[0] = R_GetTexture(basetexture);
2162                                 m.pointer_texcoord[0] = texcoord2f;
2163                                 if (r_shadow_lightcubemap != r_texture_whitecube)
2164                                 {
2165                                         m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2166 #ifdef USETEXMATRIX
2167                                         m.pointer_texcoord3f[1] = vertex3f;
2168                                         m.texmatrix[1] = r_shadow_entitytolight;
2169 #else
2170                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2171                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2172 #endif
2173                                 }
2174                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2175                         }
2176                         // this final code is shared
2177                         R_Mesh_State(&m);
2178                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2179                         VectorScale(lightcolorbase, colorscale, color2);
2180                         GL_LockArrays(firstvertex, numvertices);
2181                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2182                         {
2183                                 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2184                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2185                                 c_rt_lightmeshes++;
2186                                 c_rt_lighttris += numtriangles;
2187                         }
2188                         GL_LockArrays(0, 0);
2189                 }
2190                 if (specularscale && glosstexture != r_texture_black)
2191                 {
2192                         // FIXME: detect blendsquare!
2193                         //if (gl_support_blendsquare)
2194                         {
2195                                 colorscale = specularscale;
2196                                 GL_Color(1,1,1,1);
2197                                 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2198                                 {
2199                                         // 2/0/0/1/2 3D combine blendsquare path
2200                                         memset(&m, 0, sizeof(m));
2201                                         m.pointer_vertex = vertex3f;
2202                                         m.tex[0] = R_GetTexture(bumptexture);
2203                                         m.pointer_texcoord[0] = texcoord2f;
2204                                         m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2205                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2206                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2207                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2208                                         R_Mesh_State(&m);
2209                                         GL_ColorMask(0,0,0,1);
2210                                         // this squares the result
2211                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2212                                         GL_LockArrays(firstvertex, numvertices);
2213                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2214                                         GL_LockArrays(0, 0);
2215                                         c_rt_lightmeshes++;
2216                                         c_rt_lighttris += numtriangles;
2217
2218                                         memset(&m, 0, sizeof(m));
2219                                         m.pointer_vertex = vertex3f;
2220                                         R_Mesh_State(&m);
2221                                         GL_LockArrays(firstvertex, numvertices);
2222                                         // square alpha in framebuffer a few times to make it shiny
2223                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2224                                         // these comments are a test run through this math for intensity 0.5
2225                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2226                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2227                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2228                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2229                                         c_rt_lightmeshes++;
2230                                         c_rt_lighttris += numtriangles;
2231                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2232                                         c_rt_lightmeshes++;
2233                                         c_rt_lighttris += numtriangles;
2234                                         GL_LockArrays(0, 0);
2235
2236                                         memset(&m, 0, sizeof(m));
2237                                         m.pointer_vertex = vertex3f;
2238                                         m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2239 #ifdef USETEXMATRIX
2240                                         m.pointer_texcoord3f[0] = vertex3f;
2241                                         m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2242 #else
2243                                         m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2244                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2245 #endif
2246                                         R_Mesh_State(&m);
2247                                         GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2248                                         GL_LockArrays(firstvertex, numvertices);
2249                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2250                                         GL_LockArrays(0, 0);
2251                                         c_rt_lightmeshes++;
2252                                         c_rt_lighttris += numtriangles;
2253
2254                                         memset(&m, 0, sizeof(m));
2255                                         m.pointer_vertex = vertex3f;
2256                                         m.tex[0] = R_GetTexture(glosstexture);
2257                                         m.pointer_texcoord[0] = texcoord2f;
2258                                         if (r_shadow_lightcubemap != r_texture_whitecube)
2259                                         {
2260                                                 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2261 #ifdef USETEXMATRIX
2262                                                 m.pointer_texcoord3f[1] = vertex3f;
2263                                                 m.texmatrix[1] = r_shadow_entitytolight;
2264 #else
2265                                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2266                                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2267 #endif
2268                                         }
2269                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2270                                 }
2271                                 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2272                                 {
2273                                         // 2/0/0/2 3D combine blendsquare path
2274                                         memset(&m, 0, sizeof(m));
2275                                         m.pointer_vertex = vertex3f;
2276                                         m.tex[0] = R_GetTexture(bumptexture);
2277                                         m.pointer_texcoord[0] = texcoord2f;
2278                                         m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2279                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2280                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2281                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2282                                         R_Mesh_State(&m);
2283                                         GL_ColorMask(0,0,0,1);
2284                                         // this squares the result
2285                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2286                                         GL_LockArrays(firstvertex, numvertices);
2287                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2288                                         GL_LockArrays(0, 0);
2289                                         c_rt_lightmeshes++;
2290                                         c_rt_lighttris += numtriangles;
2291
2292                                         memset(&m, 0, sizeof(m));
2293                                         m.pointer_vertex = vertex3f;
2294                                         R_Mesh_State(&m);
2295                                         GL_LockArrays(firstvertex, numvertices);
2296                                         // square alpha in framebuffer a few times to make it shiny
2297                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2298                                         // these comments are a test run through this math for intensity 0.5
2299                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2300                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2301                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2302                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2303                                         c_rt_lightmeshes++;
2304                                         c_rt_lighttris += numtriangles;
2305                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2306                                         c_rt_lightmeshes++;
2307                                         c_rt_lighttris += numtriangles;
2308                                         GL_LockArrays(0, 0);
2309
2310                                         memset(&m, 0, sizeof(m));
2311                                         m.pointer_vertex = vertex3f;
2312                                         m.tex[0] = R_GetTexture(glosstexture);
2313                                         m.pointer_texcoord[0] = texcoord2f;
2314                                         m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2315 #ifdef USETEXMATRIX
2316                                         m.pointer_texcoord3f[1] = vertex3f;
2317                                         m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2318 #else
2319                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2320                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2321 #endif
2322                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2323                                 }
2324                                 else
2325                                 {
2326                                         // 2/0/0/2/2 2D combine blendsquare path
2327                                         memset(&m, 0, sizeof(m));
2328                                         m.pointer_vertex = vertex3f;
2329                                         m.tex[0] = R_GetTexture(bumptexture);
2330                                         m.pointer_texcoord[0] = texcoord2f;
2331                                         m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2332                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2333                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2334                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2335                                         R_Mesh_State(&m);
2336                                         GL_ColorMask(0,0,0,1);
2337                                         // this squares the result
2338                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2339                                         GL_LockArrays(firstvertex, numvertices);
2340                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2341                                         GL_LockArrays(0, 0);
2342                                         c_rt_lightmeshes++;
2343                                         c_rt_lighttris += numtriangles;
2344
2345                                         memset(&m, 0, sizeof(m));
2346                                         m.pointer_vertex = vertex3f;
2347                                         R_Mesh_State(&m);
2348                                         GL_LockArrays(firstvertex, numvertices);
2349                                         // square alpha in framebuffer a few times to make it shiny
2350                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2351                                         // these comments are a test run through this math for intensity 0.5
2352                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2353                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
2354                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2355                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2356                                         c_rt_lightmeshes++;
2357                                         c_rt_lighttris += numtriangles;
2358                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2359                                         c_rt_lightmeshes++;
2360                                         c_rt_lighttris += numtriangles;
2361                                         GL_LockArrays(0, 0);
2362
2363                                         memset(&m, 0, sizeof(m));
2364                                         m.pointer_vertex = vertex3f;
2365                                         m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2366 #ifdef USETEXMATRIX
2367                                         m.pointer_texcoord3f[0] = vertex3f;
2368                                         m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2369 #else
2370                                         m.pointer_texcoord[0] = varray_texcoord2f[0];
2371                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2372 #endif
2373                                         m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2374 #ifdef USETEXMATRIX
2375                                         m.pointer_texcoord3f[1] = vertex3f;
2376                                         m.texmatrix[1] = r_shadow_entitytoattenuationz;
2377 #else
2378                                         m.pointer_texcoord[1] = varray_texcoord2f[1];
2379                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2380 #endif
2381                                         R_Mesh_State(&m);
2382                                         GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2383                                         GL_LockArrays(firstvertex, numvertices);
2384                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2385                                         GL_LockArrays(0, 0);
2386                                         c_rt_lightmeshes++;
2387                                         c_rt_lighttris += numtriangles;
2388
2389                                         memset(&m, 0, sizeof(m));
2390                                         m.pointer_vertex = vertex3f;
2391                                         m.tex[0] = R_GetTexture(glosstexture);
2392                                         m.pointer_texcoord[0] = texcoord2f;
2393                                         if (r_shadow_lightcubemap != r_texture_whitecube)
2394                                         {
2395                                                 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2396 #ifdef USETEXMATRIX
2397                                                 m.pointer_texcoord3f[1] = vertex3f;
2398                                                 m.texmatrix[1] = r_shadow_entitytolight;
2399 #else
2400                                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2401                                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2402 #endif
2403                                         }
2404                                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2405                                 }
2406                                 R_Mesh_State(&m);
2407                                 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2408                                 VectorScale(lightcolorbase, colorscale, color2);
2409                                 GL_LockArrays(firstvertex, numvertices);
2410                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2411                                 {
2412                                         GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2413                                         R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2414                                         c_rt_lightmeshes++;
2415                                         c_rt_lighttris += numtriangles;
2416                                 }
2417                                 GL_LockArrays(0, 0);
2418                         }
2419                 }
2420         }
2421         else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
2422         {
2423                 // TODO: add direct pants/shirt rendering
2424                 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2425                         R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
2426                 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2427                         R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
2428                 if (r_shadow_rtlight->ambientscale)
2429                 {
2430                         GL_BlendFunc(GL_ONE, GL_ONE);
2431                         VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
2432                         memset(&m, 0, sizeof(m));
2433                         m.pointer_vertex = vertex3f;
2434                         m.tex[0] = R_GetTexture(basetexture);
2435                         m.pointer_texcoord[0] = texcoord2f;
2436                         if (r_textureunits.integer >= 2)
2437                         {
2438                                 // voodoo2
2439                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2440 #ifdef USETEXMATRIX
2441                                 m.pointer_texcoord3f[1] = vertex3f;
2442                                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2443 #else
2444                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2445                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2446 #endif
2447                                 if (r_textureunits.integer >= 3)
2448                                 {
2449                                         // Geforce3/Radeon class but not using dot3
2450                                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2451 #ifdef USETEXMATRIX
2452                                         m.pointer_texcoord3f[2] = vertex3f;
2453                                         m.texmatrix[2] = r_shadow_entitytoattenuationz;
2454 #else
2455                                         m.pointer_texcoord[2] = varray_texcoord2f[2];
2456                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2457 #endif
2458                                 }
2459                         }
2460                         if (r_textureunits.integer >= 3)
2461                                 m.pointer_color = NULL;
2462                         else
2463                                 m.pointer_color = varray_color4f;
2464                         R_Mesh_State(&m);
2465                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2466                         {
2467                                 color[0] = bound(0, color2[0], 1);
2468                                 color[1] = bound(0, color2[1], 1);
2469                                 color[2] = bound(0, color2[2], 1);
2470                                 if (r_textureunits.integer >= 3)
2471                                         GL_Color(color[0], color[1], color[2], 1);
2472                                 else if (r_textureunits.integer >= 2)
2473                                         R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2474                                 else
2475                                         R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2476                                 GL_LockArrays(firstvertex, numvertices);
2477                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2478                                 GL_LockArrays(0, 0);
2479                                 c_rt_lightmeshes++;
2480                                 c_rt_lighttris += numtriangles;
2481                         }
2482                 }
2483                 if (r_shadow_rtlight->diffusescale)
2484                 {
2485                         GL_BlendFunc(GL_ONE, GL_ONE);
2486                         VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
2487                         memset(&m, 0, sizeof(m));
2488                         m.pointer_vertex = vertex3f;
2489                         m.pointer_color = varray_color4f;
2490                         m.tex[0] = R_GetTexture(basetexture);
2491                         m.pointer_texcoord[0] = texcoord2f;
2492                         if (r_textureunits.integer >= 2)
2493                         {
2494                                 // voodoo2
2495                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2496 #ifdef USETEXMATRIX
2497                                 m.pointer_texcoord3f[1] = vertex3f;
2498                                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2499 #else
2500                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2501                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2502 #endif
2503                                 if (r_textureunits.integer >= 3)
2504                                 {
2505                                         // Geforce3/Radeon class but not using dot3
2506                                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2507 #ifdef USETEXMATRIX
2508                                         m.pointer_texcoord3f[2] = vertex3f;
2509                                         m.texmatrix[2] = r_shadow_entitytoattenuationz;
2510 #else
2511                                         m.pointer_texcoord[2] = varray_texcoord2f[2];
2512                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2513 #endif
2514                                 }
2515                         }
2516                         R_Mesh_State(&m);
2517                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2518                         {
2519                                 color[0] = bound(0, color2[0], 1);
2520                                 color[1] = bound(0, color2[1], 1);
2521                                 color[2] = bound(0, color2[2], 1);
2522                                 if (r_textureunits.integer >= 3)
2523                                         R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2524                                 else if (r_textureunits.integer >= 2)
2525                                         R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2526                                 else
2527                                         R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2528                                 GL_LockArrays(firstvertex, numvertices);
2529                                 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2530                                 GL_LockArrays(0, 0);
2531                                 c_rt_lightmeshes++;
2532                                 c_rt_lighttris += numtriangles;
2533                         }
2534                 }
2535         }
2536 }
2537
2538 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2539 {
2540         int j, k;
2541         float scale;
2542         R_RTLight_Uncompile(rtlight);
2543         memset(rtlight, 0, sizeof(*rtlight));
2544
2545         VectorCopy(light->origin, rtlight->shadoworigin);
2546         VectorCopy(light->color, rtlight->color);
2547         rtlight->radius = light->radius;
2548         //rtlight->cullradius = rtlight->radius;
2549         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2550         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2551         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2552         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2553         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2554         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2555         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2556         rtlight->cubemapname[0] = 0;
2557         if (light->cubemapname[0])
2558                 strcpy(rtlight->cubemapname, light->cubemapname);
2559         else if (light->cubemapnum > 0)
2560                 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2561         rtlight->shadow = light->shadow;
2562         rtlight->corona = light->corona;
2563         rtlight->style = light->style;
2564         rtlight->isstatic = isstatic;
2565         rtlight->coronasizescale = light->coronasizescale;
2566         rtlight->ambientscale = light->ambientscale;
2567         rtlight->diffusescale = light->diffusescale;
2568         rtlight->specularscale = light->specularscale;
2569         rtlight->flags = light->flags;
2570         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2571         // ConcatScale won't work here because this needs to scale rotate and
2572         // translate, not just rotate
2573         scale = 1.0f / rtlight->radius;
2574         for (k = 0;k < 3;k++)
2575                 for (j = 0;j < 4;j++)
2576                         rtlight->matrix_worldtolight.m[k][j] *= scale;
2577
2578         rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2579         rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2580         VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2581         rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2582 }
2583
2584 // compiles rtlight geometry
2585 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2586 void R_RTLight_Compile(rtlight_t *rtlight)
2587 {
2588         int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2589         entity_render_t *ent = r_refdef.worldentity;
2590         model_t *model = r_refdef.worldmodel;
2591         qbyte *data;
2592
2593         // compile the light
2594         rtlight->compiled = true;
2595         rtlight->static_numleafs = 0;
2596         rtlight->static_numleafpvsbytes = 0;
2597         rtlight->static_leaflist = NULL;
2598         rtlight->static_leafpvs = NULL;
2599         rtlight->static_numsurfaces = 0;
2600         rtlight->static_surfacelist = NULL;
2601         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2602         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2603         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2604         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2605         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2606         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2607
2608         if (model && model->GetLightInfo)
2609         {
2610                 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2611                 r_shadow_compilingrtlight = rtlight;
2612                 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->brush.num_surfaces);
2613                 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);
2614                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2615                 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2616                 rtlight->static_numleafs = numleafs;
2617                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2618                 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2619                 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2620                 rtlight->static_numsurfaces = numsurfaces;
2621                 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2622                 if (numleafs)
2623                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2624                 if (numleafpvsbytes)
2625                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2626                 if (numsurfaces)
2627                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2628                 if (model->DrawShadowVolume && rtlight->shadow)
2629                 {
2630                         rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2631                         model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2632                         rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2633                 }
2634                 if (model->DrawLight)
2635                 {
2636                         rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2637                         model->DrawLight(ent, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
2638                         rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2639                 }
2640                 // switch back to rendering when DrawShadowVolume or DrawLight is called
2641                 r_shadow_compilingrtlight = NULL;
2642         }
2643
2644
2645         // use smallest available cullradius - box radius or light radius
2646         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2647         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2648
2649         shadowmeshes = 0;
2650         shadowtris = 0;
2651         if (rtlight->static_meshchain_shadow)
2652         {
2653                 shadowmesh_t *mesh;
2654                 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2655                 {
2656                         shadowmeshes++;
2657                         shadowtris += mesh->numtriangles;
2658                 }
2659         }
2660
2661         lightmeshes = 0;
2662         lighttris = 0;
2663         if (rtlight->static_meshchain_light)
2664         {
2665                 shadowmesh_t *mesh;
2666                 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2667                 {
2668                         lightmeshes++;
2669                         lighttris += mesh->numtriangles;
2670                 }
2671         }
2672
2673         Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes), %i light triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes, lighttris, lightmeshes);
2674 }
2675
2676 void R_RTLight_Uncompile(rtlight_t *rtlight)
2677 {
2678         if (rtlight->compiled)
2679         {
2680                 if (rtlight->static_meshchain_shadow)
2681                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2682                 rtlight->static_meshchain_shadow = NULL;
2683                 if (rtlight->static_meshchain_light)
2684                         Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2685                 rtlight->static_meshchain_light = NULL;
2686                 // these allocations are grouped
2687                 if (rtlight->static_leaflist)
2688                         Mem_Free(rtlight->static_leaflist);
2689                 rtlight->static_numleafs = 0;
2690                 rtlight->static_numleafpvsbytes = 0;
2691                 rtlight->static_leaflist = NULL;
2692                 rtlight->static_leafpvs = NULL;
2693                 rtlight->static_numsurfaces = 0;
2694                 rtlight->static_surfacelist = NULL;
2695                 rtlight->compiled = false;
2696         }
2697 }
2698
2699 void R_Shadow_UncompileWorldLights(void)
2700 {
2701         dlight_t *light;
2702         for (light = r_shadow_worldlightchain;light;light = light->next)
2703                 R_RTLight_Uncompile(&light->rtlight);
2704 }
2705
2706 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2707 {
2708         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2709         vec_t relativeshadowradius;
2710         if (ent == r_refdef.worldentity)
2711         {
2712                 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2713                 {
2714                         shadowmesh_t *mesh;
2715                         R_Mesh_Matrix(&ent->matrix);
2716                         for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2717                         {
2718                                 R_Mesh_VertexPointer(mesh->vertex3f);
2719                                 GL_LockArrays(0, mesh->numverts);
2720                                 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2721                                 {
2722                                         // increment stencil if backface is behind depthbuffer
2723                                         qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2724                                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2725                                         R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2726                                         c_rtcached_shadowmeshes++;
2727                                         c_rtcached_shadowtris += mesh->numtriangles;
2728                                         // decrement stencil if frontface is behind depthbuffer
2729                                         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2730                                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2731                                 }
2732                                 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2733                                 c_rtcached_shadowmeshes++;
2734                                 c_rtcached_shadowtris += mesh->numtriangles;
2735                                 GL_LockArrays(0, 0);
2736                         }
2737                 }
2738                 else if (numsurfaces)
2739                 {
2740                         R_Mesh_Matrix(&ent->matrix);
2741                         ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2742                 }
2743         }
2744         else
2745         {
2746                 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2747                 relativeshadowradius = rtlight->radius / ent->scale;
2748                 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2749                 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2750                 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2751                 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2752                 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2753                 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2754                 R_Mesh_Matrix(&ent->matrix);
2755                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2756         }
2757 }
2758
2759 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2760 {
2761         shadowmesh_t *mesh;
2762         // set up properties for rendering light onto this entity
2763         r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2764         r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2765         r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2766         Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2767         Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2768         Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2769         Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2770         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2771         R_Mesh_Matrix(&ent->matrix);
2772         if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2773         {
2774                 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2775                 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2776                 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2777                 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2778                 {
2779                         qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2780                 }
2781         }
2782         if (ent == r_refdef.worldentity)
2783         {
2784                 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2785                 {
2786                         for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2787                                 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, r_shadow_entitylightcolor, vec3_origin, vec3_origin, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular);
2788                 }
2789                 else
2790                         ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2791         }
2792         else
2793                 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2794 }
2795
2796 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2797 {
2798         int i, usestencil;
2799         float f;
2800         vec3_t lightcolor;
2801         int numleafs, numsurfaces;
2802         int *leaflist, *surfacelist;
2803         qbyte *leafpvs;
2804         int numlightentities;
2805         int numshadowentities;
2806         entity_render_t *lightentities[MAX_EDICTS];
2807         entity_render_t *shadowentities[MAX_EDICTS];
2808
2809         // skip lights that don't light (corona only lights)
2810         if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2811                 return;
2812
2813         f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2814         VectorScale(rtlight->color, f, lightcolor);
2815         if (VectorLength2(lightcolor) < 0.01)
2816                 return;
2817         /*
2818         if (rtlight->selected)
2819         {
2820                 f = 2 + sin(realtime * M_PI * 4.0);
2821                 VectorScale(lightcolor, f, lightcolor);
2822         }
2823         */
2824
2825         // loading is done before visibility checks because loading should happen
2826         // all at once at the start of a level, not when it stalls gameplay.
2827         // (especially important to benchmarks)
2828         // compile light
2829         if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2830                 R_RTLight_Compile(rtlight);
2831         // load cubemap
2832         r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2833
2834         // if the light box is offscreen, skip it
2835         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2836                 return;
2837
2838         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2839         {
2840                 // compiled light, world available and can receive realtime lighting
2841                 // retrieve leaf information
2842                 numleafs = rtlight->static_numleafs;
2843                 leaflist = rtlight->static_leaflist;
2844                 leafpvs = rtlight->static_leafpvs;
2845                 numsurfaces = rtlight->static_numsurfaces;
2846                 surfacelist = rtlight->static_surfacelist;
2847         }
2848         else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2849         {
2850                 // dynamic light, world available and can receive realtime lighting
2851                 // calculate lit surfaces and leafs
2852                 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
2853                 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);
2854                 leaflist = r_shadow_buffer_leaflist;
2855                 leafpvs = r_shadow_buffer_leafpvs;
2856                 surfacelist = r_shadow_buffer_surfacelist;
2857                 // if the reduced leaf bounds are offscreen, skip it
2858                 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2859                         return;
2860         }
2861         else
2862         {
2863                 // no world
2864                 numleafs = 0;
2865                 leaflist = NULL;
2866                 leafpvs = NULL;
2867                 numsurfaces = 0;
2868                 surfacelist = NULL;
2869         }
2870         // check if light is illuminating any visible leafs
2871         if (numleafs)
2872         {
2873                 for (i = 0;i < numleafs;i++)
2874                         if (r_worldleafvisible[leaflist[i]])
2875                                 break;
2876                 if (i == numleafs)
2877                         return;
2878         }
2879         // set up a scissor rectangle for this light
2880         if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2881                 return;
2882
2883         numlightentities = 0;
2884         if (numsurfaces)
2885                 lightentities[numlightentities++] = r_refdef.worldentity;
2886         numshadowentities = 0;
2887         if (numsurfaces)
2888                 shadowentities[numshadowentities++] = r_refdef.worldentity;
2889         if (r_drawentities.integer)
2890         {
2891                 for (i = 0;i < r_refdef.numentities;i++)
2892                 {
2893                         entity_render_t *ent = r_refdef.entities[i];
2894                         if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2895                          && ent->model
2896                          && !(ent->flags & RENDER_TRANSPARENT)
2897                          && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2898                         {
2899                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2900                                 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2901                                         shadowentities[numshadowentities++] = ent;
2902                                 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2903                                         lightentities[numlightentities++] = ent;
2904                         }
2905                 }
2906         }
2907
2908         // return if there's nothing at all to light
2909         if (!numlightentities)
2910                 return;
2911
2912         R_Shadow_Stage_ActiveLight(rtlight);
2913         c_rt_lights++;
2914
2915         usestencil = false;
2916         if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2917         {
2918                 usestencil = true;
2919                 R_Shadow_Stage_StencilShadowVolumes();
2920                 for (i = 0;i < numshadowentities;i++)
2921                         R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2922         }
2923
2924         if (numlightentities && !visible)
2925         {
2926                 R_Shadow_Stage_Lighting(usestencil);
2927                 for (i = 0;i < numlightentities;i++)
2928                         R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2929         }
2930
2931         if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2932         {
2933                 R_Shadow_Stage_VisibleShadowVolumes();
2934                 for (i = 0;i < numshadowentities;i++)
2935                         R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2936         }
2937
2938         if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2939         {
2940                 R_Shadow_Stage_VisibleLighting(usestencil);
2941                 for (i = 0;i < numlightentities;i++)
2942                         R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2943         }
2944 }
2945
2946 void R_ShadowVolumeLighting(qboolean visible)
2947 {
2948         int lnum, flag;
2949         dlight_t *light;
2950
2951         if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2952                 R_Shadow_EditLights_Reload_f();
2953
2954         R_Shadow_Stage_Begin();
2955
2956         flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2957         if (r_shadow_debuglight.integer >= 0)
2958         {
2959                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2960                         if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2961                                 R_DrawRTLight(&light->rtlight, visible);
2962         }
2963         else
2964                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2965                         if (light->flags & flag)
2966                                 R_DrawRTLight(&light->rtlight, visible);
2967         if (r_rtdlight)
2968                 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2969                         R_DrawRTLight(&light->rtlight, visible);
2970
2971         R_Shadow_Stage_End();
2972 }
2973
2974 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2975 typedef struct suffixinfo_s
2976 {
2977         char *suffix;
2978         qboolean flipx, flipy, flipdiagonal;
2979 }
2980 suffixinfo_t;
2981 static suffixinfo_t suffix[3][6] =
2982 {
2983         {
2984                 {"px",   false, false, false},
2985                 {"nx",   false, false, false},
2986                 {"py",   false, false, false},
2987                 {"ny",   false, false, false},
2988                 {"pz",   false, false, false},
2989                 {"nz",   false, false, false}
2990         },
2991         {
2992                 {"posx", false, false, false},
2993                 {"negx", false, false, false},
2994                 {"posy", false, false, false},
2995                 {"negy", false, false, false},
2996                 {"posz", false, false, false},
2997                 {"negz", false, false, false}
2998         },
2999         {
3000                 {"rt",    true, false,  true},
3001                 {"lf",   false,  true,  true},
3002                 {"ft",    true,  true, false},
3003                 {"bk",   false, false, false},
3004                 {"up",    true, false,  true},
3005                 {"dn",    true, false,  true}
3006         }
3007 };
3008
3009 static int componentorder[4] = {0, 1, 2, 3};
3010
3011 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3012 {
3013         int i, j, cubemapsize;
3014         qbyte *cubemappixels, *image_rgba;
3015         rtexture_t *cubemaptexture;
3016         char name[256];
3017         // must start 0 so the first loadimagepixels has no requested width/height
3018         cubemapsize = 0;
3019         cubemappixels = NULL;
3020         cubemaptexture = NULL;
3021         // keep trying different suffix groups (posx, px, rt) until one loads
3022         for (j = 0;j < 3 && !cubemappixels;j++)
3023         {
3024                 // load the 6 images in the suffix group
3025                 for (i = 0;i < 6;i++)
3026                 {
3027                         // generate an image name based on the base and and suffix
3028                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3029                         // load it
3030                         if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3031                         {
3032                                 // an image loaded, make sure width and height are equal
3033                                 if (image_width == image_height)
3034                                 {
3035                                         // if this is the first image to load successfully, allocate the cubemap memory
3036                                         if (!cubemappixels && image_width >= 1)
3037                                         {
3038                                                 cubemapsize = image_width;
3039                                                 // note this clears to black, so unavailable sides are black
3040                                                 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3041                                         }
3042                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3043                                         if (cubemappixels)
3044                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_rgba, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
3045                                 }
3046                                 else
3047                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3048                                 // free the image
3049                                 Mem_Free(image_rgba);
3050                         }
3051                 }
3052         }
3053         // if a cubemap loaded, upload it
3054         if (cubemappixels)
3055         {
3056                 if (!r_shadow_filters_texturepool)
3057                         r_shadow_filters_texturepool = R_AllocTexturePool();
3058                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3059                 Mem_Free(cubemappixels);
3060         }
3061         else
3062         {
3063                 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3064                 for (j = 0;j < 3;j++)
3065                         for (i = 0;i < 6;i++)
3066                                 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3067                 Con_Print(" and was unable to find any of them.\n");
3068         }
3069         return cubemaptexture;
3070 }
3071
3072 rtexture_t *R_Shadow_Cubemap(const char *basename)
3073 {
3074         int i;
3075         for (i = 0;i < numcubemaps;i++)
3076                 if (!strcasecmp(cubemaps[i].basename, basename))
3077                         return cubemaps[i].texture;
3078         if (i >= MAX_CUBEMAPS)
3079                 return r_texture_whitecube;
3080         numcubemaps++;
3081         strcpy(cubemaps[i].basename, basename);
3082         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3083         return cubemaps[i].texture;
3084 }
3085
3086 void R_Shadow_FreeCubemaps(void)
3087 {
3088         numcubemaps = 0;
3089         R_FreeTexturePool(&r_shadow_filters_texturepool);
3090 }
3091
3092 dlight_t *R_Shadow_NewWorldLight(void)
3093 {
3094         dlight_t *light;
3095         light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3096         light->next = r_shadow_worldlightchain;
3097         r_shadow_worldlightchain = light;
3098         return light;
3099 }
3100
3101 void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
3102 {
3103         VectorCopy(origin, light->origin);
3104         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3105         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3106         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3107         light->color[0] = max(color[0], 0);
3108         light->color[1] = max(color[1], 0);
3109         light->color[2] = max(color[2], 0);
3110         light->radius = max(radius, 0);
3111         light->style = style;
3112         if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3113         {
3114                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3115                 light->style = 0;
3116         }
3117         light->shadow = shadowenable;
3118         light->corona = corona;
3119         if (!cubemapname)
3120                 cubemapname = "";
3121         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3122         light->coronasizescale = coronasizescale;
3123         light->ambientscale = ambientscale;
3124         light->diffusescale = diffusescale;
3125         light->specularscale = specularscale;
3126         light->flags = flags;
3127         Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3128
3129         R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3130 }
3131
3132 void R_Shadow_FreeWorldLight(dlight_t *light)
3133 {
3134         dlight_t **lightpointer;
3135         R_RTLight_Uncompile(&light->rtlight);
3136         for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3137         if (*lightpointer != light)
3138                 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3139         *lightpointer = light->next;
3140         Mem_Free(light);
3141 }
3142
3143 void R_Shadow_ClearWorldLights(void)
3144 {
3145         while (r_shadow_worldlightchain)
3146                 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3147         r_shadow_selectedlight = NULL;
3148         R_Shadow_FreeCubemaps();
3149 }
3150
3151 void R_Shadow_SelectLight(dlight_t *light)
3152 {
3153         if (r_shadow_selectedlight)
3154                 r_shadow_selectedlight->selected = false;
3155         r_shadow_selectedlight = light;
3156         if (r_shadow_selectedlight)
3157                 r_shadow_selectedlight->selected = true;
3158 }
3159
3160 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3161 {
3162         float scale = r_editlights_cursorgrid.value * 0.5f;
3163         R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
3164 }
3165
3166 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3167 {
3168         float intensity;
3169         const dlight_t *light;
3170         light = calldata1;
3171         intensity = 0.5;
3172         if (light->selected)
3173                 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3174         if (!light->shadow)
3175                 intensity *= 0.5f;
3176         R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
3177 }
3178
3179 void R_Shadow_DrawLightSprites(void)
3180 {
3181         int i;
3182         cachepic_t *pic;
3183         dlight_t *light;
3184
3185         for (i = 0;i < 5;i++)
3186         {
3187                 lighttextures[i] = NULL;
3188                 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3189                         lighttextures[i] = pic->tex;
3190         }
3191
3192         for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3193                 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3194         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3195 }
3196
3197 void R_Shadow_SelectLightInView(void)
3198 {
3199         float bestrating, rating, temp[3];
3200         dlight_t *best, *light;
3201         best = NULL;
3202         bestrating = 0;
3203         for (light = r_shadow_worldlightchain;light;light = light->next)
3204         {
3205                 VectorSubtract(light->origin, r_vieworigin, temp);
3206                 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3207                 if (rating >= 0.95)
3208                 {
3209                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3210                         if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3211                         {
3212                                 bestrating = rating;
3213                                 best = light;
3214                         }
3215                 }
3216         }
3217         R_Shadow_SelectLight(best);
3218 }
3219
3220 void R_Shadow_LoadWorldLights(void)
3221 {
3222         int n, a, style, shadow, flags;
3223         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3224         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3225         if (r_refdef.worldmodel == NULL)
3226         {
3227                 Con_Print("No map loaded.\n");
3228                 return;
3229         }
3230         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3231         strlcat (name, ".rtlights", sizeof (name));
3232         lightsstring = FS_LoadFile(name, tempmempool, false);
3233         if (lightsstring)
3234         {
3235                 s = lightsstring;
3236                 n = 0;
3237                 while (*s)
3238                 {
3239                         t = s;
3240                         /*
3241                         shadow = true;
3242                         for (;COM_Parse(t, true) && strcmp(
3243                         if (COM_Parse(t, true))
3244                         {
3245                                 if (com_token[0] == '!')
3246                                 {
3247                                         shadow = false;
3248                                         origin[0] = atof(com_token+1);
3249                                 }
3250                                 else
3251                                         origin[0] = atof(com_token);
3252                                 if (Com_Parse(t
3253                         }
3254                         */
3255                         t = s;
3256                         while (*s && *s != '\n' && *s != '\r')
3257                                 s++;
3258                         if (!*s)
3259                                 break;
3260                         tempchar = *s;
3261                         shadow = true;
3262                         // check for modifier flags
3263                         if (*t == '!')
3264                         {
3265                                 shadow = false;
3266                                 t++;
3267                         }
3268                         *s = 0;
3269                         a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
3270                         *s = tempchar;
3271                         if (a < 18)
3272                                 flags = LIGHTFLAG_REALTIMEMODE;
3273                         if (a < 17)
3274                                 specularscale = 1;
3275                         if (a < 16)
3276                                 diffusescale = 1;
3277                         if (a < 15)
3278                                 ambientscale = 0;
3279                         if (a < 14)
3280                                 coronasizescale = 0.25f;
3281                         if (a < 13)
3282                                 VectorClear(angles);
3283                         if (a < 10)
3284                                 corona = 0;
3285                         if (a < 9 || !strcmp(cubemapname, "\"\""))
3286                                 cubemapname[0] = 0;
3287                         // remove quotes on cubemapname
3288                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3289                         {
3290                                 cubemapname[strlen(cubemapname)-1] = 0;
3291                                 strcpy(cubemapname, cubemapname + 1);
3292                         }
3293                         if (a < 8)
3294                         {
3295                                 Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
3296                                 break;
3297                         }
3298                         VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3299                         radius *= r_editlights_rtlightssizescale.value;
3300                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3301                         if (*s == '\r')
3302                                 s++;
3303                         if (*s == '\n')
3304                                 s++;
3305                         n++;
3306                 }
3307                 if (*s)
3308                         Con_Printf("invalid rtlights file \"%s\"\n", name);
3309                 Mem_Free(lightsstring);
3310         }
3311 }
3312
3313 void R_Shadow_SaveWorldLights(void)
3314 {
3315         dlight_t *light;
3316         int bufchars, bufmaxchars;
3317         char *buf, *oldbuf;
3318         char name[MAX_QPATH];
3319         char line[1024];
3320         if (!r_shadow_worldlightchain)
3321                 return;
3322         if (r_refdef.worldmodel == NULL)
3323         {
3324                 Con_Print("No map loaded.\n");
3325                 return;
3326         }
3327         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3328         strlcat (name, ".rtlights", sizeof (name));
3329         bufchars = bufmaxchars = 0;
3330         buf = NULL;
3331         for (light = r_shadow_worldlightchain;light;light = light->next)
3332         {
3333                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3334                         sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3335                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3336                         sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3337                 else
3338                         sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
3339                 if (bufchars + (int) strlen(line) > bufmaxchars)
3340                 {
3341                         bufmaxchars = bufchars + strlen(line) + 2048;
3342                         oldbuf = buf;
3343                         buf = Mem_Alloc(tempmempool, bufmaxchars);
3344                         if (oldbuf)
3345                         {
3346                                 if (bufchars)
3347                                         memcpy(buf, oldbuf, bufchars);
3348                                 Mem_Free(oldbuf);
3349                         }
3350                 }
3351                 if (strlen(line))
3352                 {
3353                         memcpy(buf + bufchars, line, strlen(line));
3354                         bufchars += strlen(line);
3355                 }
3356         }
3357         if (bufchars)
3358                 FS_WriteFile(name, buf, bufchars);
3359         if (buf)
3360                 Mem_Free(buf);
3361 }
3362
3363 void R_Shadow_LoadLightsFile(void)
3364 {
3365         int n, a, style;
3366         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3367         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3368         if (r_refdef.worldmodel == NULL)
3369         {
3370                 Con_Print("No map loaded.\n");
3371                 return;
3372         }
3373         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3374         strlcat (name, ".lights", sizeof (name));
3375         lightsstring = FS_LoadFile(name, tempmempool, false);
3376         if (lightsstring)
3377         {
3378                 s = lightsstring;
3379                 n = 0;
3380                 while (*s)
3381                 {
3382                         t = s;
3383                         while (*s && *s != '\n' && *s != '\r')
3384                                 s++;
3385                         if (!*s)
3386                                 break;
3387                         tempchar = *s;
3388                         *s = 0;
3389                         a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
3390                         *s = tempchar;
3391                         if (a < 14)
3392                         {
3393                                 Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
3394                                 break;
3395                         }
3396                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3397                         radius = bound(15, radius, 4096);
3398                         VectorScale(color, (2.0f / (8388608.0f)), color);
3399                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3400                         if (*s == '\r')
3401                                 s++;
3402                         if (*s == '\n')
3403                                 s++;
3404                         n++;
3405                 }
3406                 if (*s)
3407                         Con_Printf("invalid lights file \"%s\"\n", name);
3408                 Mem_Free(lightsstring);
3409         }
3410 }
3411
3412 // tyrlite/hmap2 light types in the delay field
3413 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3414
3415 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3416 {
3417         int entnum, style, islight, skin, pflags, effects, type, n;
3418         char *entfiledata;
3419         const char *data;
3420         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3421         char key[256], value[1024];
3422
3423         if (r_refdef.worldmodel == NULL)
3424         {
3425                 Con_Print("No map loaded.\n");
3426                 return;
3427         }
3428         // try to load a .ent file first
3429         FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3430         strlcat (key, ".ent", sizeof (key));
3431         data = entfiledata = FS_LoadFile(key, tempmempool, true);
3432         // and if that is not found, fall back to the bsp file entity string
3433         if (!data)
3434                 data = r_refdef.worldmodel->brush.entities;
3435         if (!data)
3436                 return;
3437         for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3438         {
3439                 type = LIGHTTYPE_MINUSX;
3440                 origin[0] = origin[1] = origin[2] = 0;
3441                 originhack[0] = originhack[1] = originhack[2] = 0;
3442                 angles[0] = angles[1] = angles[2] = 0;
3443                 color[0] = color[1] = color[2] = 1;
3444                 light[0] = light[1] = light[2] = 1;light[3] = 300;
3445                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3446                 fadescale = 1;
3447                 lightscale = 1;
3448                 style = 0;
3449                 skin = 0;
3450                 pflags = 0;
3451                 effects = 0;
3452                 islight = false;
3453                 while (1)
3454                 {
3455                         if (!COM_ParseToken(&data, false))
3456                                 break; // error
3457                         if (com_token[0] == '}')
3458                                 break; // end of entity
3459                         if (com_token[0] == '_')
3460                                 strcpy(key, com_token + 1);
3461                         else
3462                                 strcpy(key, com_token);
3463                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
3464                                 key[strlen(key)-1] = 0;
3465                         if (!COM_ParseToken(&data, false))
3466                                 break; // error
3467                         strcpy(value, com_token);
3468
3469                         // now that we have the key pair worked out...
3470                         if (!strcmp("light", key))
3471                         {
3472                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3473                                 if (n == 1)
3474                                 {
3475                                         // quake
3476                                         light[0] = vec[0] * (1.0f / 256.0f);
3477                                         light[1] = vec[0] * (1.0f / 256.0f);
3478                                         light[2] = vec[0] * (1.0f / 256.0f);
3479                                         light[3] = vec[0];
3480                                 }
3481                                 else if (n == 4)
3482                                 {
3483                                         // halflife
3484                                         light[0] = vec[0] * (1.0f / 255.0f);
3485                                         light[1] = vec[1] * (1.0f / 255.0f);
3486                                         light[2] = vec[2] * (1.0f / 255.0f);
3487                                         light[3] = vec[3];
3488                                 }
3489                         }
3490                         else if (!strcmp("delay", key))
3491                                 type = atoi(value);
3492                         else if (!strcmp("origin", key))
3493                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3494                         else if (!strcmp("angle", key))
3495                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3496                         else if (!strcmp("angles", key))
3497                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3498                         else if (!strcmp("color", key))
3499                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3500                         else if (!strcmp("wait", key))
3501                                 fadescale = atof(value);
3502                         else if (!strcmp("classname", key))
3503                         {
3504                                 if (!strncmp(value, "light", 5))
3505                                 {
3506                                         islight = true;
3507                                         if (!strcmp(value, "light_fluoro"))
3508                                         {
3509                                                 originhack[0] = 0;
3510                                                 originhack[1] = 0;
3511                                                 originhack[2] = 0;
3512                                                 overridecolor[0] = 1;
3513                                                 overridecolor[1] = 1;
3514                                                 overridecolor[2] = 1;
3515                                         }
3516                                         if (!strcmp(value, "light_fluorospark"))
3517                                         {
3518                                                 originhack[0] = 0;
3519                                                 originhack[1] = 0;
3520                                                 originhack[2] = 0;
3521                                                 overridecolor[0] = 1;
3522                                                 overridecolor[1] = 1;
3523                                                 overridecolor[2] = 1;
3524                                         }
3525                                         if (!strcmp(value, "light_globe"))
3526                                         {
3527                                                 originhack[0] = 0;
3528                                                 originhack[1] = 0;
3529                                                 originhack[2] = 0;
3530                                                 overridecolor[0] = 1;
3531                                                 overridecolor[1] = 0.8;
3532                                                 overridecolor[2] = 0.4;
3533                                         }
3534                                         if (!strcmp(value, "light_flame_large_yellow"))
3535                                         {
3536                                                 originhack[0] = 0;
3537                                                 originhack[1] = 0;
3538                                                 originhack[2] = 48;
3539                                                 overridecolor[0] = 1;
3540                                                 overridecolor[1] = 0.5;
3541                                                 overridecolor[2] = 0.1;
3542                                         }
3543                                         if (!strcmp(value, "light_flame_small_yellow"))
3544                                         {
3545                                                 originhack[0] = 0;
3546                                                 originhack[1] = 0;
3547                                                 originhack[2] = 40;
3548                                                 overridecolor[0] = 1;
3549                                                 overridecolor[1] = 0.5;
3550                                                 overridecolor[2] = 0.1;
3551                                         }
3552                                         if (!strcmp(value, "light_torch_small_white"))
3553                                         {
3554                                                 originhack[0] = 0;
3555                                                 originhack[1] = 0;
3556                                                 originhack[2] = 40;
3557                                                 overridecolor[0] = 1;
3558                                                 overridecolor[1] = 0.5;
3559                                                 overridecolor[2] = 0.1;
3560                                         }
3561                                         if (!strcmp(value, "light_torch_small_walltorch"))
3562                                         {
3563                                                 originhack[0] = 0;
3564                                                 originhack[1] = 0;
3565                                                 originhack[2] = 40;
3566                                                 overridecolor[0] = 1;
3567                                                 overridecolor[1] = 0.5;
3568                                                 overridecolor[2] = 0.1;
3569                                         }
3570                                 }
3571                         }
3572                         else if (!strcmp("style", key))
3573                                 style = atoi(value);
3574                         else if (r_refdef.worldmodel->type == mod_brushq3)
3575                         {
3576                                 if (!strcmp("scale", key))
3577                                         lightscale = atof(value);
3578                                 if (!strcmp("fade", key))
3579                                         fadescale = atof(value);
3580                         }
3581                         else if (!strcmp("skin", key))
3582                                 skin = (int)atof(value);
3583                         else if (!strcmp("pflags", key))
3584                                 pflags = (int)atof(value);
3585                         else if (!strcmp("effects", key))
3586                                 effects = (int)atof(value);
3587                 }
3588                 if (!islight)
3589                         continue;
3590                 if (lightscale <= 0)
3591                         lightscale = 1;
3592                 if (fadescale <= 0)
3593                         fadescale = 1;
3594                 if (color[0] == color[1] && color[0] == color[2])
3595                 {
3596                         color[0] *= overridecolor[0];
3597                         color[1] *= overridecolor[1];
3598                         color[2] *= overridecolor[2];
3599                 }
3600                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3601                 color[0] = color[0] * light[0];
3602                 color[1] = color[1] * light[1];
3603                 color[2] = color[2] * light[2];
3604                 switch (type)
3605                 {
3606                 case LIGHTTYPE_MINUSX:
3607                         break;
3608                 case LIGHTTYPE_RECIPX:
3609                         radius *= 2;
3610                         VectorScale(color, (1.0f / 16.0f), color);
3611                         break;
3612                 case LIGHTTYPE_RECIPXX:
3613                         radius *= 2;
3614                         VectorScale(color, (1.0f / 16.0f), color);
3615                         break;
3616                 default:
3617                 case LIGHTTYPE_NONE:
3618                         break;
3619                 case LIGHTTYPE_SUN:
3620                         break;
3621                 case LIGHTTYPE_MINUSXX:
3622                         break;
3623                 }
3624                 VectorAdd(origin, originhack, origin);
3625                 if (radius >= 1)
3626                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3627         }
3628         if (entfiledata)
3629                 Mem_Free(entfiledata);
3630 }
3631
3632
3633 void R_Shadow_SetCursorLocationForView(void)
3634 {
3635         vec_t dist, push;
3636         vec3_t dest, endpos;
3637         trace_t trace;
3638         VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3639         trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3640         if (trace.fraction < 1)
3641         {
3642                 dist = trace.fraction * r_editlights_cursordistance.value;
3643                 push = r_editlights_cursorpushback.value;
3644                 if (push > dist)
3645                         push = dist;
3646                 push = -push;
3647                 VectorMA(trace.endpos, push, r_viewforward, endpos);
3648                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3649         }
3650         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3651         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3652         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3653 }
3654
3655 void R_Shadow_UpdateWorldLightSelection(void)
3656 {
3657         if (r_editlights.integer)
3658         {
3659                 R_Shadow_SetCursorLocationForView();
3660                 R_Shadow_SelectLightInView();
3661                 R_Shadow_DrawLightSprites();
3662         }
3663         else
3664                 R_Shadow_SelectLight(NULL);
3665 }
3666
3667 void R_Shadow_EditLights_Clear_f(void)
3668 {
3669         R_Shadow_ClearWorldLights();
3670 }
3671
3672 void R_Shadow_EditLights_Reload_f(void)
3673 {
3674         if (!r_refdef.worldmodel)
3675                 return;
3676         strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3677         R_Shadow_ClearWorldLights();
3678         R_Shadow_LoadWorldLights();
3679         if (r_shadow_worldlightchain == NULL)
3680         {
3681                 R_Shadow_LoadLightsFile();
3682                 if (r_shadow_worldlightchain == NULL)
3683                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3684         }
3685 }
3686
3687 void R_Shadow_EditLights_Save_f(void)
3688 {
3689         if (!r_refdef.worldmodel)
3690                 return;
3691         R_Shadow_SaveWorldLights();
3692 }
3693
3694 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3695 {
3696         R_Shadow_ClearWorldLights();
3697         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3698 }
3699
3700 void R_Shadow_EditLights_ImportLightsFile_f(void)
3701 {
3702         R_Shadow_ClearWorldLights();
3703         R_Shadow_LoadLightsFile();
3704 }
3705
3706 void R_Shadow_EditLights_Spawn_f(void)
3707 {
3708         vec3_t color;
3709         if (!r_editlights.integer)
3710         {
3711                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3712                 return;
3713         }
3714         if (Cmd_Argc() != 1)
3715         {
3716                 Con_Print("r_editlights_spawn does not take parameters\n");
3717                 return;
3718         }
3719         color[0] = color[1] = color[2] = 1;
3720         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3721 }
3722
3723 void R_Shadow_EditLights_Edit_f(void)
3724 {
3725         vec3_t origin, angles, color;
3726         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3727         int style, shadows, flags, normalmode, realtimemode;
3728         char cubemapname[1024];
3729         if (!r_editlights.integer)
3730         {
3731                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3732                 return;
3733         }
3734         if (!r_shadow_selectedlight)
3735         {
3736                 Con_Print("No selected light.\n");
3737                 return;
3738         }
3739         VectorCopy(r_shadow_selectedlight->origin, origin);
3740         VectorCopy(r_shadow_selectedlight->angles, angles);
3741         VectorCopy(r_shadow_selectedlight->color, color);
3742         radius = r_shadow_selectedlight->radius;
3743         style = r_shadow_selectedlight->style;
3744         if (r_shadow_selectedlight->cubemapname)
3745                 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3746         else
3747                 cubemapname[0] = 0;
3748         shadows = r_shadow_selectedlight->shadow;
3749         corona = r_shadow_selectedlight->corona;
3750         coronasizescale = r_shadow_selectedlight->coronasizescale;
3751         ambientscale = r_shadow_selectedlight->ambientscale;
3752         diffusescale = r_shadow_selectedlight->diffusescale;
3753         specularscale = r_shadow_selectedlight->specularscale;
3754         flags = r_shadow_selectedlight->flags;
3755         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3756         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3757         if (!strcmp(Cmd_Argv(1), "origin"))
3758         {
3759                 if (Cmd_Argc() != 5)
3760                 {
3761                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3762                         return;
3763                 }
3764                 origin[0] = atof(Cmd_Argv(2));
3765                 origin[1] = atof(Cmd_Argv(3));
3766                 origin[2] = atof(Cmd_Argv(4));
3767         }
3768         else if (!strcmp(Cmd_Argv(1), "originx"))
3769         {
3770                 if (Cmd_Argc() != 3)
3771                 {
3772                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3773                         return;
3774                 }
3775                 origin[0] = atof(Cmd_Argv(2));
3776         }
3777         else if (!strcmp(Cmd_Argv(1), "originy"))
3778         {
3779                 if (Cmd_Argc() != 3)
3780                 {
3781                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3782                         return;
3783                 }
3784                 origin[1] = atof(Cmd_Argv(2));
3785         }
3786         else if (!strcmp(Cmd_Argv(1), "originz"))
3787         {
3788                 if (Cmd_Argc() != 3)
3789                 {
3790                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3791                         return;
3792                 }
3793                 origin[2] = atof(Cmd_Argv(2));
3794         }
3795         else if (!strcmp(Cmd_Argv(1), "move"))
3796         {
3797                 if (Cmd_Argc() != 5)
3798                 {
3799                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3800                         return;
3801                 }
3802                 origin[0] += atof(Cmd_Argv(2));
3803                 origin[1] += atof(Cmd_Argv(3));
3804                 origin[2] += atof(Cmd_Argv(4));
3805         }
3806         else if (!strcmp(Cmd_Argv(1), "movex"))
3807         {
3808                 if (Cmd_Argc() != 3)
3809                 {
3810                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3811                         return;
3812                 }
3813                 origin[0] += atof(Cmd_Argv(2));
3814         }
3815         else if (!strcmp(Cmd_Argv(1), "movey"))
3816         {
3817                 if (Cmd_Argc() != 3)
3818                 {
3819                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3820                         return;
3821                 }
3822                 origin[1] += atof(Cmd_Argv(2));
3823         }
3824         else if (!strcmp(Cmd_Argv(1), "movez"))
3825         {
3826                 if (Cmd_Argc() != 3)
3827                 {
3828                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3829                         return;
3830                 }
3831                 origin[2] += atof(Cmd_Argv(2));
3832         }
3833         else if (!strcmp(Cmd_Argv(1), "angles"))
3834         {
3835                 if (Cmd_Argc() != 5)
3836                 {
3837                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3838                         return;
3839                 }
3840                 angles[0] = atof(Cmd_Argv(2));
3841                 angles[1] = atof(Cmd_Argv(3));
3842                 angles[2] = atof(Cmd_Argv(4));
3843         }
3844         else if (!strcmp(Cmd_Argv(1), "anglesx"))
3845         {
3846                 if (Cmd_Argc() != 3)
3847                 {
3848                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3849                         return;
3850                 }
3851                 angles[0] = atof(Cmd_Argv(2));
3852         }
3853         else if (!strcmp(Cmd_Argv(1), "anglesy"))
3854         {
3855                 if (Cmd_Argc() != 3)
3856                 {
3857                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3858                         return;
3859                 }
3860                 angles[1] = atof(Cmd_Argv(2));
3861         }
3862         else if (!strcmp(Cmd_Argv(1), "anglesz"))
3863         {
3864                 if (Cmd_Argc() != 3)
3865                 {
3866                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3867                         return;
3868                 }
3869                 angles[2] = atof(Cmd_Argv(2));
3870         }
3871         else if (!strcmp(Cmd_Argv(1), "color"))
3872         {
3873                 if (Cmd_Argc() != 5)
3874                 {
3875                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3876                         return;
3877                 }
3878                 color[0] = atof(Cmd_Argv(2));
3879                 color[1] = atof(Cmd_Argv(3));
3880                 color[2] = atof(Cmd_Argv(4));
3881         }
3882         else if (!strcmp(Cmd_Argv(1), "radius"))
3883         {
3884                 if (Cmd_Argc() != 3)
3885                 {
3886                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3887                         return;
3888                 }
3889                 radius = atof(Cmd_Argv(2));
3890         }
3891         else if (!strcmp(Cmd_Argv(1), "style"))
3892         {
3893                 if (Cmd_Argc() != 3)
3894                 {
3895                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3896                         return;
3897                 }
3898                 style = atoi(Cmd_Argv(2));
3899         }
3900         else if (!strcmp(Cmd_Argv(1), "cubemap"))
3901         {
3902                 if (Cmd_Argc() > 3)
3903                 {
3904                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3905                         return;
3906                 }
3907                 if (Cmd_Argc() == 3)
3908                         strcpy(cubemapname, Cmd_Argv(2));
3909                 else
3910                         cubemapname[0] = 0;
3911         }
3912         else if (!strcmp(Cmd_Argv(1), "shadows"))
3913         {
3914                 if (Cmd_Argc() != 3)
3915                 {
3916                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3917                         return;
3918                 }
3919                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3920         }
3921         else if (!strcmp(Cmd_Argv(1), "corona"))
3922         {
3923                 if (Cmd_Argc() != 3)
3924                 {
3925                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3926                         return;
3927                 }
3928                 corona = atof(Cmd_Argv(2));
3929         }
3930         else if (!strcmp(Cmd_Argv(1), "coronasize"))
3931         {
3932                 if (Cmd_Argc() != 3)
3933                 {
3934                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3935                         return;
3936                 }
3937                 coronasizescale = atof(Cmd_Argv(2));
3938         }
3939         else if (!strcmp(Cmd_Argv(1), "ambient"))
3940         {
3941                 if (Cmd_Argc() != 3)
3942                 {
3943                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3944                         return;
3945                 }
3946                 ambientscale = atof(Cmd_Argv(2));
3947         }
3948         else if (!strcmp(Cmd_Argv(1), "diffuse"))
3949         {
3950                 if (Cmd_Argc() != 3)
3951                 {
3952                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3953                         return;
3954                 }
3955                 diffusescale = atof(Cmd_Argv(2));
3956         }
3957         else if (!strcmp(Cmd_Argv(1), "specular"))
3958         {
3959                 if (Cmd_Argc() != 3)
3960                 {
3961                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3962                         return;
3963                 }
3964                 specularscale = atof(Cmd_Argv(2));
3965         }
3966         else if (!strcmp(Cmd_Argv(1), "normalmode"))
3967         {
3968                 if (Cmd_Argc() != 3)
3969                 {
3970                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3971                         return;
3972                 }
3973                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3974         }
3975         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3976         {
3977                 if (Cmd_Argc() != 3)
3978                 {
3979                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3980                         return;
3981                 }
3982                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3983         }
3984         else
3985         {
3986                 Con_Print("usage: r_editlights_edit [property] [value]\n");
3987                 Con_Print("Selected light's properties:\n");
3988                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3989                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3990                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3991                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
3992                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
3993                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
3994                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3995                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
3996                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
3997                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
3998                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
3999                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
4000                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4001                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4002                 return;
4003         }
4004         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4005         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4006 }
4007
4008 void R_Shadow_EditLights_EditAll_f(void)
4009 {
4010         dlight_t *light;
4011
4012         if (!r_editlights.integer)
4013         {
4014                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4015                 return;
4016         }
4017
4018         for (light = r_shadow_worldlightchain;light;light = light->next)
4019         {
4020                 R_Shadow_SelectLight(light);
4021                 R_Shadow_EditLights_Edit_f();
4022         }
4023 }
4024
4025 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4026 {
4027         int lightnumber, lightcount;
4028         dlight_t *light;
4029         float x, y;
4030         char temp[256];
4031         if (!r_editlights.integer)
4032                 return;
4033         x = 0;
4034         y = con_vislines;
4035         lightnumber = -1;
4036         lightcount = 0;
4037         for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4038                 if (light == r_shadow_selectedlight)
4039                         lightnumber = lightcount;
4040         sprintf(temp, "Cursor  %f %f %f  Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4041         if (r_shadow_selectedlight == NULL)
4042                 return;
4043         sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4044         sprintf(temp, "Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4045         sprintf(temp, "Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4046         sprintf(temp, "Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4047         sprintf(temp, "Radius       : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4048         sprintf(temp, "Corona       : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4049         sprintf(temp, "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4050         sprintf(temp, "Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4051         sprintf(temp, "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4052         sprintf(temp, "CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4053         sprintf(temp, "Ambient      : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4054         sprintf(temp, "Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4055         sprintf(temp, "Specular     : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4056         sprintf(temp, "NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4057         sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4058 }
4059
4060 void R_Shadow_EditLights_ToggleShadow_f(void)
4061 {
4062         if (!r_editlights.integer)
4063         {
4064                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
4065                 return;
4066         }
4067         if (!r_shadow_selectedlight)
4068         {
4069                 Con_Print("No selected light.\n");
4070                 return;
4071         }
4072         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
4073 }
4074
4075 void R_Shadow_EditLights_ToggleCorona_f(void)
4076 {
4077         if (!r_editlights.integer)
4078         {
4079                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
4080                 return;
4081         }
4082         if (!r_shadow_selectedlight)
4083         {
4084                 Con_Print("No selected light.\n");
4085                 return;
4086         }
4087         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
4088 }
4089
4090 void R_Shadow_EditLights_Remove_f(void)
4091 {
4092         if (!r_editlights.integer)
4093         {
4094                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
4095                 return;
4096         }
4097         if (!r_shadow_selectedlight)
4098         {
4099                 Con_Print("No selected light.\n");
4100                 return;
4101         }
4102         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4103         r_shadow_selectedlight = NULL;
4104 }
4105
4106 void R_Shadow_EditLights_Help_f(void)
4107 {
4108         Con_Print(
4109 "Documentation on r_editlights system:\n"
4110 "Settings:\n"
4111 "r_editlights : enable/disable editing mode\n"
4112 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4113 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4114 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4115 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4116 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4117 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4118 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4119 "Commands:\n"
4120 "r_editlights_help : this help\n"
4121 "r_editlights_clear : remove all lights\n"
4122 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4123 "r_editlights_save : save to .rtlights file\n"
4124 "r_editlights_spawn : create a light with default settings\n"
4125 "r_editlights_edit command : edit selected light - more documentation below\n"
4126 "r_editlights_remove : remove selected light\n"
4127 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4128 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4129 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4130 "Edit commands:\n"
4131 "origin x y z : set light location\n"
4132 "originx x: set x component of light location\n"
4133 "originy y: set y component of light location\n"
4134 "originz z: set z component of light location\n"
4135 "move x y z : adjust light location\n"
4136 "movex x: adjust x component of light location\n"
4137 "movey y: adjust y component of light location\n"
4138 "movez z: adjust z component of light location\n"
4139 "angles x y z : set light angles\n"
4140 "anglesx x: set x component of light angles\n"
4141 "anglesy y: set y component of light angles\n"
4142 "anglesz z: set z component of light angles\n"
4143 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4144 "radius radius : set radius (size) of light\n"
4145 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4146 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4147 "shadows 1/0 : turn on/off shadows\n"
4148 "corona n : set corona intensity\n"
4149 "coronasize n : set corona size (0-1)\n"
4150 "ambient n : set ambient intensity (0-1)\n"
4151 "diffuse n : set diffuse intensity (0-1)\n"
4152 "specular n : set specular intensity (0-1)\n"
4153 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4154 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4155 "<nothing> : print light properties to console\n"
4156         );
4157 }
4158
4159 void R_Shadow_EditLights_CopyInfo_f(void)
4160 {
4161         if (!r_editlights.integer)
4162         {
4163                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
4164                 return;
4165         }
4166         if (!r_shadow_selectedlight)
4167         {
4168                 Con_Print("No selected light.\n");
4169                 return;
4170         }
4171         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4172         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4173         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4174         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4175         if (r_shadow_selectedlight->cubemapname)
4176                 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4177         else
4178                 r_shadow_bufferlight.cubemapname[0] = 0;
4179         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4180         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4181         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4182         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4183         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4184         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4185         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4186 }
4187
4188 void R_Shadow_EditLights_PasteInfo_f(void)
4189 {
4190         if (!r_editlights.integer)
4191         {
4192                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
4193                 return;
4194         }
4195         if (!r_shadow_selectedlight)
4196         {
4197                 Con_Print("No selected light.\n");
4198                 return;
4199         }
4200         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
4201 }
4202
4203 void R_Shadow_EditLights_Init(void)
4204 {
4205         Cvar_RegisterVariable(&r_editlights);
4206         Cvar_RegisterVariable(&r_editlights_cursordistance);
4207         Cvar_RegisterVariable(&r_editlights_cursorpushback);
4208         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4209         Cvar_RegisterVariable(&r_editlights_cursorgrid);
4210         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4211         Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4212         Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4213         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4214         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4215         Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4216         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4217         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4218         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4219         Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4220         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4221         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4222         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4223         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4224         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4225         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4226         Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);
4227 }
4228