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