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