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