]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
changed renderer to check ent->colormap_pantscolor and ent->colormap_shirtcolor inste...
[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         if ((VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor)) >= (1.0f / 1048576.0f))
2558         {
2559                 lightcolorpants[0] = r_shadow_rtlight->currentcolor[0] * ent->colormap_pantscolor[0] * texture->currentalpha;
2560                 lightcolorpants[1] = r_shadow_rtlight->currentcolor[1] * ent->colormap_pantscolor[1] * texture->currentalpha;
2561                 lightcolorpants[2] = r_shadow_rtlight->currentcolor[2] * ent->colormap_pantscolor[2] * texture->currentalpha;
2562                 lightcolorshirt[0] = r_shadow_rtlight->currentcolor[0] * ent->colormap_shirtcolor[0] * texture->currentalpha;
2563                 lightcolorshirt[1] = r_shadow_rtlight->currentcolor[1] * ent->colormap_shirtcolor[1] * texture->currentalpha;
2564                 lightcolorshirt[2] = r_shadow_rtlight->currentcolor[2] * ent->colormap_shirtcolor[2] * texture->currentalpha;
2565                 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2566                         return;
2567                 basetexture = texture->skin.base;
2568                 switch (r_shadow_rendermode)
2569                 {
2570                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2571                         R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
2572                         break;
2573                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2574                         R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
2575                         break;
2576                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2577                         R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
2578                         break;
2579                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2580                         R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
2581                         break;
2582                 default:
2583                         Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2584                         break;
2585                 }
2586         }
2587         else
2588         {
2589                 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2590                         return;
2591                 basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
2592                 switch (r_shadow_rendermode)
2593                 {
2594                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2595                         R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale);
2596                         break;
2597                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2598                         R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale);
2599                         break;
2600                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2601                         R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale);
2602                         break;
2603                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2604                         R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale);
2605                         break;
2606                 default:
2607                         Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2608                         break;
2609                 }
2610         }
2611 }
2612
2613 void R_RTLight_Update(dlight_t *light, int isstatic)
2614 {
2615         int j, k;
2616         float scale;
2617         rtlight_t *rtlight = &light->rtlight;
2618         R_RTLight_Uncompile(rtlight);
2619         memset(rtlight, 0, sizeof(*rtlight));
2620
2621         VectorCopy(light->origin, rtlight->shadoworigin);
2622         VectorCopy(light->color, rtlight->color);
2623         rtlight->radius = light->radius;
2624         //rtlight->cullradius = rtlight->radius;
2625         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2626         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2627         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2628         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2629         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2630         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2631         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2632         rtlight->cubemapname[0] = 0;
2633         if (light->cubemapname[0])
2634                 strcpy(rtlight->cubemapname, light->cubemapname);
2635         else if (light->cubemapnum > 0)
2636                 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2637         rtlight->shadow = light->shadow;
2638         rtlight->corona = light->corona;
2639         rtlight->style = light->style;
2640         rtlight->isstatic = isstatic;
2641         rtlight->coronasizescale = light->coronasizescale;
2642         rtlight->ambientscale = light->ambientscale;
2643         rtlight->diffusescale = light->diffusescale;
2644         rtlight->specularscale = light->specularscale;
2645         rtlight->flags = light->flags;
2646         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2647         // ConcatScale won't work here because this needs to scale rotate and
2648         // translate, not just rotate
2649         scale = 1.0f / rtlight->radius;
2650         for (k = 0;k < 3;k++)
2651                 for (j = 0;j < 4;j++)
2652                         rtlight->matrix_worldtolight.m[k][j] *= scale;
2653
2654         rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2655         rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2656         VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2657         rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2658 }
2659
2660 // compiles rtlight geometry
2661 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2662 void R_RTLight_Compile(rtlight_t *rtlight)
2663 {
2664         int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2665         entity_render_t *ent = r_refdef.worldentity;
2666         model_t *model = r_refdef.worldmodel;
2667         unsigned char *data;
2668
2669         // compile the light
2670         rtlight->compiled = true;
2671         rtlight->static_numleafs = 0;
2672         rtlight->static_numleafpvsbytes = 0;
2673         rtlight->static_leaflist = NULL;
2674         rtlight->static_leafpvs = NULL;
2675         rtlight->static_numsurfaces = 0;
2676         rtlight->static_surfacelist = NULL;
2677         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2678         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2679         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2680         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2681         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2682         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2683
2684         if (model && model->GetLightInfo)
2685         {
2686                 // this variable must be set for the CompileShadowVolume code
2687                 r_shadow_compilingrtlight = rtlight;
2688                 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2689                 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);
2690                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2691                 data = (unsigned char *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2692                 rtlight->static_numleafs = numleafs;
2693                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2694                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2695                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2696                 rtlight->static_numsurfaces = numsurfaces;
2697                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2698                 if (numleafs)
2699                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2700                 if (numleafpvsbytes)
2701                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2702                 if (numsurfaces)
2703                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2704                 if (model->CompileShadowVolume && rtlight->shadow)
2705                         model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2706                 // now we're done compiling the rtlight
2707                 r_shadow_compilingrtlight = NULL;
2708         }
2709
2710
2711         // use smallest available cullradius - box radius or light radius
2712         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2713         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2714
2715         shadowmeshes = 0;
2716         shadowtris = 0;
2717         if (rtlight->static_meshchain_shadow)
2718         {
2719                 shadowmesh_t *mesh;
2720                 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2721                 {
2722                         shadowmeshes++;
2723                         shadowtris += mesh->numtriangles;
2724                 }
2725         }
2726
2727         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);
2728 }
2729
2730 void R_RTLight_Uncompile(rtlight_t *rtlight)
2731 {
2732         if (rtlight->compiled)
2733         {
2734                 if (rtlight->static_meshchain_shadow)
2735                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2736                 rtlight->static_meshchain_shadow = NULL;
2737                 // these allocations are grouped
2738                 if (rtlight->static_leaflist)
2739                         Mem_Free(rtlight->static_leaflist);
2740                 rtlight->static_numleafs = 0;
2741                 rtlight->static_numleafpvsbytes = 0;
2742                 rtlight->static_leaflist = NULL;
2743                 rtlight->static_leafpvs = NULL;
2744                 rtlight->static_numsurfaces = 0;
2745                 rtlight->static_surfacelist = NULL;
2746                 rtlight->compiled = false;
2747         }
2748 }
2749
2750 void R_Shadow_UncompileWorldLights(void)
2751 {
2752         dlight_t *light;
2753         for (light = r_shadow_worldlightchain;light;light = light->next)
2754                 R_RTLight_Uncompile(&light->rtlight);
2755 }
2756
2757 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2758 {
2759         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2760         vec_t relativeshadowradius;
2761         if (ent == r_refdef.worldentity)
2762         {
2763                 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2764                 {
2765                         shadowmesh_t *mesh;
2766                         R_Mesh_Matrix(&ent->matrix);
2767                         for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2768                         {
2769                                 renderstats.lights_shadowtriangles += mesh->numtriangles;
2770                                 R_Mesh_VertexPointer(mesh->vertex3f);
2771                                 GL_LockArrays(0, mesh->numverts);
2772                                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2773                                 {
2774                                         // decrement stencil if backface is behind depthbuffer
2775                                         qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2776                                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2777                                         R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2778                                         // increment stencil if frontface is behind depthbuffer
2779                                         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2780                                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2781                                 }
2782                                 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2783                                 GL_LockArrays(0, 0);
2784                         }
2785                 }
2786                 else if (numsurfaces)
2787                 {
2788                         R_Mesh_Matrix(&ent->matrix);
2789                         ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2790                 }
2791         }
2792         else
2793         {
2794                 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2795                 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2796                 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2797                 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2798                 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2799                 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2800                 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2801                 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2802                 R_Mesh_Matrix(&ent->matrix);
2803                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2804         }
2805 }
2806
2807 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2808 {
2809         // set up properties for rendering light onto this entity
2810         Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2811         Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2812         Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2813         Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2814         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2815         R_Mesh_Matrix(&ent->matrix);
2816         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2817         {
2818                 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2819                 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2820                 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2821                 {
2822                         qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2823                 }
2824         }
2825 }
2826
2827 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2828 {
2829         R_Shadow_SetupEntityLight(ent);
2830         if (ent == r_refdef.worldentity)
2831                 ent->model->DrawLight(ent, numsurfaces, surfacelist);
2832         else
2833                 ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
2834 }
2835
2836 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2837 {
2838         int i, usestencil;
2839         float f;
2840         int numleafs, numsurfaces;
2841         int *leaflist, *surfacelist;
2842         unsigned char *leafpvs;
2843         int numlightentities;
2844         int numshadowentities;
2845         entity_render_t *lightentities[MAX_EDICTS];
2846         entity_render_t *shadowentities[MAX_EDICTS];
2847
2848         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2849         // skip lights that are basically invisible (color 0 0 0)
2850         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2851                 return;
2852
2853         // loading is done before visibility checks because loading should happen
2854         // all at once at the start of a level, not when it stalls gameplay.
2855         // (especially important to benchmarks)
2856         // compile light
2857         if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2858                 R_RTLight_Compile(rtlight);
2859         // load cubemap
2860         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2861
2862         // look up the light style value at this time
2863         f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2864         VectorScale(rtlight->color, f, rtlight->currentcolor);
2865         /*
2866         if (rtlight->selected)
2867         {
2868                 f = 2 + sin(realtime * M_PI * 4.0);
2869                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2870         }
2871         */
2872
2873         // if lightstyle is currently off, don't draw the light
2874         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2875                 return;
2876
2877         // if the light box is offscreen, skip it
2878         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2879                 return;
2880
2881         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2882         {
2883                 // compiled light, world available and can receive realtime lighting
2884                 // retrieve leaf information
2885                 numleafs = rtlight->static_numleafs;
2886                 leaflist = rtlight->static_leaflist;
2887                 leafpvs = rtlight->static_leafpvs;
2888                 numsurfaces = rtlight->static_numsurfaces;
2889                 surfacelist = rtlight->static_surfacelist;
2890         }
2891         else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2892         {
2893                 // dynamic light, world available and can receive realtime lighting
2894                 // calculate lit surfaces and leafs
2895                 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2896                 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);
2897                 leaflist = r_shadow_buffer_leaflist;
2898                 leafpvs = r_shadow_buffer_leafpvs;
2899                 surfacelist = r_shadow_buffer_surfacelist;
2900                 // if the reduced leaf bounds are offscreen, skip it
2901                 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2902                         return;
2903         }
2904         else
2905         {
2906                 // no world
2907                 numleafs = 0;
2908                 leaflist = NULL;
2909                 leafpvs = NULL;
2910                 numsurfaces = 0;
2911                 surfacelist = NULL;
2912         }
2913         // check if light is illuminating any visible leafs
2914         if (numleafs)
2915         {
2916                 for (i = 0;i < numleafs;i++)
2917                         if (r_worldleafvisible[leaflist[i]])
2918                                 break;
2919                 if (i == numleafs)
2920                         return;
2921         }
2922         // set up a scissor rectangle for this light
2923         if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2924                 return;
2925
2926         // make a list of lit entities and shadow casting entities
2927         numlightentities = 0;
2928         numshadowentities = 0;
2929         // don't count the world unless some surfaces are actually lit
2930         if (numsurfaces)
2931         {
2932                 lightentities[numlightentities++] = r_refdef.worldentity;
2933                 shadowentities[numshadowentities++] = r_refdef.worldentity;
2934         }
2935         // add dynamic entities that are lit by the light
2936         if (r_drawentities.integer)
2937         {
2938                 for (i = 0;i < r_refdef.numentities;i++)
2939                 {
2940                         entity_render_t *ent = r_refdef.entities[i];
2941                         if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2942                          && ent->model
2943                          && !(ent->flags & RENDER_TRANSPARENT)
2944                          && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2945                         {
2946                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2947                                 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2948                                         shadowentities[numshadowentities++] = ent;
2949                                 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2950                                         lightentities[numlightentities++] = ent;
2951                         }
2952                 }
2953         }
2954
2955         // return if there's nothing at all to light
2956         if (!numlightentities)
2957                 return;
2958
2959         // make this the active rtlight for rendering purposes
2960         R_Shadow_RenderMode_ActiveLight(rtlight);
2961         // count this light in the r_speeds
2962         renderstats.lights++;
2963
2964         // draw stencil shadow volumes to mask off pixels that are in shadow
2965         // so that they won't receive lighting
2966         usestencil = false;
2967         if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2968         {
2969                 usestencil = true;
2970                 R_Shadow_RenderMode_StencilShadowVolumes();
2971                 for (i = 0;i < numshadowentities;i++)
2972                         R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2973         }
2974
2975         // draw lighting in the unmasked areas
2976         if (numlightentities && !visible)
2977         {
2978                 R_Shadow_RenderMode_Lighting(usestencil, false);
2979                 for (i = 0;i < numlightentities;i++)
2980                         R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2981         }
2982
2983         // optionally draw visible shape of the shadow volumes
2984         // for performance analysis by level designers
2985         if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2986         {
2987                 R_Shadow_RenderMode_VisibleShadowVolumes();
2988                 for (i = 0;i < numshadowentities;i++)
2989                         R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2990         }
2991
2992         // optionally draw the illuminated areas
2993         // for performance analysis by level designers
2994         if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2995         {
2996                 R_Shadow_RenderMode_VisibleLighting(usestencil, false);
2997                 for (i = 0;i < numlightentities;i++)
2998                         R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2999         }
3000 }
3001
3002 void R_ShadowVolumeLighting(qboolean visible)
3003 {
3004         int lnum, flag;
3005         dlight_t *light;
3006
3007         if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3008                 R_Shadow_EditLights_Reload_f();
3009
3010         R_Shadow_RenderMode_Begin();
3011
3012         flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3013         if (r_shadow_debuglight.integer >= 0)
3014         {
3015                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3016                         if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3017                                 R_DrawRTLight(&light->rtlight, visible);
3018         }
3019         else
3020                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3021                         if (light->flags & flag)
3022                                 R_DrawRTLight(&light->rtlight, visible);
3023         if (r_rtdlight)
3024                 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3025                         R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
3026
3027         R_Shadow_RenderMode_End();
3028 }
3029
3030 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3031 typedef struct suffixinfo_s
3032 {
3033         char *suffix;
3034         qboolean flipx, flipy, flipdiagonal;
3035 }
3036 suffixinfo_t;
3037 static suffixinfo_t suffix[3][6] =
3038 {
3039         {
3040                 {"px",   false, false, false},
3041                 {"nx",   false, false, false},
3042                 {"py",   false, false, false},
3043                 {"ny",   false, false, false},
3044                 {"pz",   false, false, false},
3045                 {"nz",   false, false, false}
3046         },
3047         {
3048                 {"posx", false, false, false},
3049                 {"negx", false, false, false},
3050                 {"posy", false, false, false},
3051                 {"negy", false, false, false},
3052                 {"posz", false, false, false},
3053                 {"negz", false, false, false}
3054         },
3055         {
3056                 {"rt",    true, false,  true},
3057                 {"lf",   false,  true,  true},
3058                 {"ft",    true,  true, false},
3059                 {"bk",   false, false, false},
3060                 {"up",    true, false,  true},
3061                 {"dn",    true, false,  true}
3062         }
3063 };
3064
3065 static int componentorder[4] = {0, 1, 2, 3};
3066
3067 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3068 {
3069         int i, j, cubemapsize;
3070         unsigned char *cubemappixels, *image_rgba;
3071         rtexture_t *cubemaptexture;
3072         char name[256];
3073         // must start 0 so the first loadimagepixels has no requested width/height
3074         cubemapsize = 0;
3075         cubemappixels = NULL;
3076         cubemaptexture = NULL;
3077         // keep trying different suffix groups (posx, px, rt) until one loads
3078         for (j = 0;j < 3 && !cubemappixels;j++)
3079         {
3080                 // load the 6 images in the suffix group
3081                 for (i = 0;i < 6;i++)
3082                 {
3083                         // generate an image name based on the base and and suffix
3084                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3085                         // load it
3086                         if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3087                         {
3088                                 // an image loaded, make sure width and height are equal
3089                                 if (image_width == image_height)
3090                                 {
3091                                         // if this is the first image to load successfully, allocate the cubemap memory
3092                                         if (!cubemappixels && image_width >= 1)
3093                                         {
3094                                                 cubemapsize = image_width;
3095                                                 // note this clears to black, so unavailable sides are black
3096                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3097                                         }
3098                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3099                                         if (cubemappixels)
3100                                                 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);
3101                                 }
3102                                 else
3103                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3104                                 // free the image
3105                                 Mem_Free(image_rgba);
3106                         }
3107                 }
3108         }
3109         // if a cubemap loaded, upload it
3110         if (cubemappixels)
3111         {
3112                 if (!r_shadow_filters_texturepool)
3113                         r_shadow_filters_texturepool = R_AllocTexturePool();
3114                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3115                 Mem_Free(cubemappixels);
3116         }
3117         else
3118         {
3119                 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3120                 for (j = 0;j < 3;j++)
3121                         for (i = 0;i < 6;i++)
3122                                 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3123                 Con_Print(" and was unable to find any of them.\n");
3124         }
3125         return cubemaptexture;
3126 }
3127
3128 rtexture_t *R_Shadow_Cubemap(const char *basename)
3129 {
3130         int i;
3131         for (i = 0;i < numcubemaps;i++)
3132                 if (!strcasecmp(cubemaps[i].basename, basename))
3133                         return cubemaps[i].texture;
3134         if (i >= MAX_CUBEMAPS)
3135                 return r_texture_whitecube;
3136         numcubemaps++;
3137         strcpy(cubemaps[i].basename, basename);
3138         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3139         if (!cubemaps[i].texture)
3140                 cubemaps[i].texture = r_texture_whitecube;
3141         return cubemaps[i].texture;
3142 }
3143
3144 void R_Shadow_FreeCubemaps(void)
3145 {
3146         numcubemaps = 0;
3147         R_FreeTexturePool(&r_shadow_filters_texturepool);
3148 }
3149
3150 dlight_t *R_Shadow_NewWorldLight(void)
3151 {
3152         dlight_t *light;
3153         light = (dlight_t *)Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3154         light->next = r_shadow_worldlightchain;
3155         r_shadow_worldlightchain = light;
3156         return light;
3157 }
3158
3159 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)
3160 {
3161         VectorCopy(origin, light->origin);
3162         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3163         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3164         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3165         light->color[0] = max(color[0], 0);
3166         light->color[1] = max(color[1], 0);
3167         light->color[2] = max(color[2], 0);
3168         light->radius = max(radius, 0);
3169         light->style = style;
3170         if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3171         {
3172                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3173                 light->style = 0;
3174         }
3175         light->shadow = shadowenable;
3176         light->corona = corona;
3177         if (!cubemapname)
3178                 cubemapname = "";
3179         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3180         light->coronasizescale = coronasizescale;
3181         light->ambientscale = ambientscale;
3182         light->diffusescale = diffusescale;
3183         light->specularscale = specularscale;
3184         light->flags = flags;
3185         Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3186
3187         R_RTLight_Update(light, true);
3188 }
3189
3190 void R_Shadow_FreeWorldLight(dlight_t *light)
3191 {
3192         dlight_t **lightpointer;
3193         R_RTLight_Uncompile(&light->rtlight);
3194         for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3195         if (*lightpointer != light)
3196                 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3197         *lightpointer = light->next;
3198         Mem_Free(light);
3199 }
3200
3201 void R_Shadow_ClearWorldLights(void)
3202 {
3203         while (r_shadow_worldlightchain)
3204                 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3205         r_shadow_selectedlight = NULL;
3206         R_Shadow_FreeCubemaps();
3207 }
3208
3209 void R_Shadow_SelectLight(dlight_t *light)
3210 {
3211         if (r_shadow_selectedlight)
3212                 r_shadow_selectedlight->selected = false;
3213         r_shadow_selectedlight = light;
3214         if (r_shadow_selectedlight)
3215                 r_shadow_selectedlight->selected = true;
3216 }
3217
3218 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
3219 {
3220         float scale = r_editlights_cursorgrid.value * 0.5f;
3221         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);
3222 }
3223
3224 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
3225 {
3226         float intensity;
3227         const dlight_t *light = (dlight_t *)ent;
3228         intensity = 0.5;
3229         if (light->selected)
3230                 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3231         if (!light->shadow)
3232                 intensity *= 0.5f;
3233         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);
3234 }
3235
3236 void R_Shadow_DrawLightSprites(void)
3237 {
3238         int i;
3239         cachepic_t *pic;
3240         dlight_t *light;
3241
3242         for (i = 0;i < 5;i++)
3243         {
3244                 lighttextures[i] = NULL;
3245                 if ((pic = Draw_CachePic(va("gfx/crosshair%i", i + 1), true)))
3246                         lighttextures[i] = pic->tex;
3247         }
3248
3249         for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3250                 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, i % 5, &light->rtlight);
3251         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3252 }
3253
3254 void R_Shadow_SelectLightInView(void)
3255 {
3256         float bestrating, rating, temp[3];
3257         dlight_t *best, *light;
3258         best = NULL;
3259         bestrating = 0;
3260         for (light = r_shadow_worldlightchain;light;light = light->next)
3261         {
3262                 VectorSubtract(light->origin, r_vieworigin, temp);
3263                 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3264                 if (rating >= 0.95)
3265                 {
3266                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3267                         if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3268                         {
3269                                 bestrating = rating;
3270                                 best = light;
3271                         }
3272                 }
3273         }
3274         R_Shadow_SelectLight(best);
3275 }
3276
3277 void R_Shadow_LoadWorldLights(void)
3278 {
3279         int n, a, style, shadow, flags;
3280         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3281         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3282         if (r_refdef.worldmodel == NULL)
3283         {
3284                 Con_Print("No map loaded.\n");
3285                 return;
3286         }
3287         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3288         strlcat (name, ".rtlights", sizeof (name));
3289         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3290         if (lightsstring)
3291         {
3292                 s = lightsstring;
3293                 n = 0;
3294                 while (*s)
3295                 {
3296                         t = s;
3297                         /*
3298                         shadow = true;
3299                         for (;COM_Parse(t, true) && strcmp(
3300                         if (COM_Parse(t, true))
3301                         {
3302                                 if (com_token[0] == '!')
3303                                 {
3304                                         shadow = false;
3305                                         origin[0] = atof(com_token+1);
3306                                 }
3307                                 else
3308                                         origin[0] = atof(com_token);
3309                                 if (Com_Parse(t
3310                         }
3311                         */
3312                         t = s;
3313                         while (*s && *s != '\n' && *s != '\r')
3314                                 s++;
3315                         if (!*s)
3316                                 break;
3317                         tempchar = *s;
3318                         shadow = true;
3319                         // check for modifier flags
3320                         if (*t == '!')
3321                         {
3322                                 shadow = false;
3323                                 t++;
3324                         }
3325                         *s = 0;
3326                         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);
3327                         *s = tempchar;
3328                         if (a < 18)
3329                                 flags = LIGHTFLAG_REALTIMEMODE;
3330                         if (a < 17)
3331                                 specularscale = 1;
3332                         if (a < 16)
3333                                 diffusescale = 1;
3334                         if (a < 15)
3335                                 ambientscale = 0;
3336                         if (a < 14)
3337                                 coronasizescale = 0.25f;
3338                         if (a < 13)
3339                                 VectorClear(angles);
3340                         if (a < 10)
3341                                 corona = 0;
3342                         if (a < 9 || !strcmp(cubemapname, "\"\""))
3343                                 cubemapname[0] = 0;
3344                         // remove quotes on cubemapname
3345                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3346                         {
3347                                 cubemapname[strlen(cubemapname)-1] = 0;
3348                                 strcpy(cubemapname, cubemapname + 1);
3349                         }
3350                         if (a < 8)
3351                         {
3352                                 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);
3353                                 break;
3354                         }
3355                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3356                         if (*s == '\r')
3357                                 s++;
3358                         if (*s == '\n')
3359                                 s++;
3360                         n++;
3361                 }
3362                 if (*s)
3363                         Con_Printf("invalid rtlights file \"%s\"\n", name);
3364                 Mem_Free(lightsstring);
3365         }
3366 }
3367
3368 void R_Shadow_SaveWorldLights(void)
3369 {
3370         dlight_t *light;
3371         size_t bufchars, bufmaxchars;
3372         char *buf, *oldbuf;
3373         char name[MAX_QPATH];
3374         char line[MAX_INPUTLINE];
3375         if (!r_shadow_worldlightchain)
3376                 return;
3377         if (r_refdef.worldmodel == NULL)
3378         {
3379                 Con_Print("No map loaded.\n");
3380                 return;
3381         }
3382         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3383         strlcat (name, ".rtlights", sizeof (name));
3384         bufchars = bufmaxchars = 0;
3385         buf = NULL;
3386         for (light = r_shadow_worldlightchain;light;light = light->next)
3387         {
3388                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3389                         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);
3390                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3391                         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]);
3392                 else
3393                         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);
3394                 if (bufchars + strlen(line) > bufmaxchars)
3395                 {
3396                         bufmaxchars = bufchars + strlen(line) + 2048;
3397                         oldbuf = buf;
3398                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3399                         if (oldbuf)
3400                         {
3401                                 if (bufchars)
3402                                         memcpy(buf, oldbuf, bufchars);
3403                                 Mem_Free(oldbuf);
3404                         }
3405                 }
3406                 if (strlen(line))
3407                 {
3408                         memcpy(buf + bufchars, line, strlen(line));
3409                         bufchars += strlen(line);
3410                 }
3411         }
3412         if (bufchars)
3413                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3414         if (buf)
3415                 Mem_Free(buf);
3416 }
3417
3418 void R_Shadow_LoadLightsFile(void)
3419 {
3420         int n, a, style;
3421         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3422         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3423         if (r_refdef.worldmodel == NULL)
3424         {
3425                 Con_Print("No map loaded.\n");
3426                 return;
3427         }
3428         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3429         strlcat (name, ".lights", sizeof (name));
3430         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3431         if (lightsstring)
3432         {
3433                 s = lightsstring;
3434                 n = 0;
3435                 while (*s)
3436                 {
3437                         t = s;
3438                         while (*s && *s != '\n' && *s != '\r')
3439                                 s++;
3440                         if (!*s)
3441                                 break;
3442                         tempchar = *s;
3443                         *s = 0;
3444                         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);
3445                         *s = tempchar;
3446                         if (a < 14)
3447                         {
3448                                 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);
3449                                 break;
3450                         }
3451                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3452                         radius = bound(15, radius, 4096);
3453                         VectorScale(color, (2.0f / (8388608.0f)), color);
3454                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3455                         if (*s == '\r')
3456                                 s++;
3457                         if (*s == '\n')
3458                                 s++;
3459                         n++;
3460                 }
3461                 if (*s)
3462                         Con_Printf("invalid lights file \"%s\"\n", name);
3463                 Mem_Free(lightsstring);
3464         }
3465 }
3466
3467 // tyrlite/hmap2 light types in the delay field
3468 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3469
3470 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3471 {
3472         int entnum, style, islight, skin, pflags, effects, type, n;
3473         char *entfiledata;
3474         const char *data;
3475         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3476         char key[256], value[MAX_INPUTLINE];
3477
3478         if (r_refdef.worldmodel == NULL)
3479         {
3480                 Con_Print("No map loaded.\n");
3481                 return;
3482         }
3483         // try to load a .ent file first
3484         FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3485         strlcat (key, ".ent", sizeof (key));
3486         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3487         // and if that is not found, fall back to the bsp file entity string
3488         if (!data)
3489                 data = r_refdef.worldmodel->brush.entities;
3490         if (!data)
3491                 return;
3492         for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3493         {
3494                 type = LIGHTTYPE_MINUSX;
3495                 origin[0] = origin[1] = origin[2] = 0;
3496                 originhack[0] = originhack[1] = originhack[2] = 0;
3497                 angles[0] = angles[1] = angles[2] = 0;
3498                 color[0] = color[1] = color[2] = 1;
3499                 light[0] = light[1] = light[2] = 1;light[3] = 300;
3500                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3501                 fadescale = 1;
3502                 lightscale = 1;
3503                 style = 0;
3504                 skin = 0;
3505                 pflags = 0;
3506                 effects = 0;
3507                 islight = false;
3508                 while (1)
3509                 {
3510                         if (!COM_ParseToken(&data, false))
3511                                 break; // error
3512                         if (com_token[0] == '}')
3513                                 break; // end of entity
3514                         if (com_token[0] == '_')
3515                                 strcpy(key, com_token + 1);
3516                         else
3517                                 strcpy(key, com_token);
3518                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
3519                                 key[strlen(key)-1] = 0;
3520                         if (!COM_ParseToken(&data, false))
3521                                 break; // error
3522                         strcpy(value, com_token);
3523
3524                         // now that we have the key pair worked out...
3525                         if (!strcmp("light", key))
3526                         {
3527                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3528                                 if (n == 1)
3529                                 {
3530                                         // quake
3531                                         light[0] = vec[0] * (1.0f / 256.0f);
3532                                         light[1] = vec[0] * (1.0f / 256.0f);
3533                                         light[2] = vec[0] * (1.0f / 256.0f);
3534                                         light[3] = vec[0];
3535                                 }
3536                                 else if (n == 4)
3537                                 {
3538                                         // halflife
3539                                         light[0] = vec[0] * (1.0f / 255.0f);
3540                                         light[1] = vec[1] * (1.0f / 255.0f);
3541                                         light[2] = vec[2] * (1.0f / 255.0f);
3542                                         light[3] = vec[3];
3543                                 }
3544                         }
3545                         else if (!strcmp("delay", key))
3546                                 type = atoi(value);
3547                         else if (!strcmp("origin", key))
3548                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3549                         else if (!strcmp("angle", key))
3550                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3551                         else if (!strcmp("angles", key))
3552                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3553                         else if (!strcmp("color", key))
3554                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3555                         else if (!strcmp("wait", key))
3556                                 fadescale = atof(value);
3557                         else if (!strcmp("classname", key))
3558                         {
3559                                 if (!strncmp(value, "light", 5))
3560                                 {
3561                                         islight = true;
3562                                         if (!strcmp(value, "light_fluoro"))
3563                                         {
3564                                                 originhack[0] = 0;
3565                                                 originhack[1] = 0;
3566                                                 originhack[2] = 0;
3567                                                 overridecolor[0] = 1;
3568                                                 overridecolor[1] = 1;
3569                                                 overridecolor[2] = 1;
3570                                         }
3571                                         if (!strcmp(value, "light_fluorospark"))
3572                                         {
3573                                                 originhack[0] = 0;
3574                                                 originhack[1] = 0;
3575                                                 originhack[2] = 0;
3576                                                 overridecolor[0] = 1;
3577                                                 overridecolor[1] = 1;
3578                                                 overridecolor[2] = 1;
3579                                         }
3580                                         if (!strcmp(value, "light_globe"))
3581                                         {
3582                                                 originhack[0] = 0;
3583                                                 originhack[1] = 0;
3584                                                 originhack[2] = 0;
3585                                                 overridecolor[0] = 1;
3586                                                 overridecolor[1] = 0.8;
3587                                                 overridecolor[2] = 0.4;
3588                                         }
3589                                         if (!strcmp(value, "light_flame_large_yellow"))
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_flame_small_yellow"))
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                                         if (!strcmp(value, "light_torch_small_white"))
3608                                         {
3609                                                 originhack[0] = 0;
3610                                                 originhack[1] = 0;
3611                                                 originhack[2] = 0;
3612                                                 overridecolor[0] = 1;
3613                                                 overridecolor[1] = 0.5;
3614                                                 overridecolor[2] = 0.1;
3615                                         }
3616                                         if (!strcmp(value, "light_torch_small_walltorch"))
3617                                         {
3618                                                 originhack[0] = 0;
3619                                                 originhack[1] = 0;
3620                                                 originhack[2] = 0;
3621                                                 overridecolor[0] = 1;
3622                                                 overridecolor[1] = 0.5;
3623                                                 overridecolor[2] = 0.1;
3624                                         }
3625                                 }
3626                         }
3627                         else if (!strcmp("style", key))
3628                                 style = atoi(value);
3629                         else if (!strcmp("skin", key))
3630                                 skin = (int)atof(value);
3631                         else if (!strcmp("pflags", key))
3632                                 pflags = (int)atof(value);
3633                         else if (!strcmp("effects", key))
3634                                 effects = (int)atof(value);
3635                         else if (r_refdef.worldmodel->type == mod_brushq3)
3636                         {
3637                                 if (!strcmp("scale", key))
3638                                         lightscale = atof(value);
3639                                 if (!strcmp("fade", key))
3640                                         fadescale = atof(value);
3641                         }
3642                 }
3643                 if (!islight)
3644                         continue;
3645                 if (lightscale <= 0)
3646                         lightscale = 1;
3647                 if (fadescale <= 0)
3648                         fadescale = 1;
3649                 if (color[0] == color[1] && color[0] == color[2])
3650                 {
3651                         color[0] *= overridecolor[0];
3652                         color[1] *= overridecolor[1];
3653                         color[2] *= overridecolor[2];
3654                 }
3655                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3656                 color[0] = color[0] * light[0];
3657                 color[1] = color[1] * light[1];
3658                 color[2] = color[2] * light[2];
3659                 switch (type)
3660                 {
3661                 case LIGHTTYPE_MINUSX:
3662                         break;
3663                 case LIGHTTYPE_RECIPX:
3664                         radius *= 2;
3665                         VectorScale(color, (1.0f / 16.0f), color);
3666                         break;
3667                 case LIGHTTYPE_RECIPXX:
3668                         radius *= 2;
3669                         VectorScale(color, (1.0f / 16.0f), color);
3670                         break;
3671                 default:
3672                 case LIGHTTYPE_NONE:
3673                         break;
3674                 case LIGHTTYPE_SUN:
3675                         break;
3676                 case LIGHTTYPE_MINUSXX:
3677                         break;
3678                 }
3679                 VectorAdd(origin, originhack, origin);
3680                 if (radius >= 1)
3681                         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);
3682         }
3683         if (entfiledata)
3684                 Mem_Free(entfiledata);
3685 }
3686
3687
3688 void R_Shadow_SetCursorLocationForView(void)
3689 {
3690         vec_t dist, push;
3691         vec3_t dest, endpos;
3692         trace_t trace;
3693         VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3694         trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3695         if (trace.fraction < 1)
3696         {
3697                 dist = trace.fraction * r_editlights_cursordistance.value;
3698                 push = r_editlights_cursorpushback.value;
3699                 if (push > dist)
3700                         push = dist;
3701                 push = -push;
3702                 VectorMA(trace.endpos, push, r_viewforward, endpos);
3703                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3704         }
3705         else
3706         {
3707                 VectorClear( endpos );
3708         }
3709         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3710         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3711         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3712 }
3713
3714 void R_Shadow_UpdateWorldLightSelection(void)
3715 {
3716         if (r_editlights.integer)
3717         {
3718                 R_Shadow_SetCursorLocationForView();
3719                 R_Shadow_SelectLightInView();
3720                 R_Shadow_DrawLightSprites();
3721         }
3722         else
3723                 R_Shadow_SelectLight(NULL);
3724 }
3725
3726 void R_Shadow_EditLights_Clear_f(void)
3727 {
3728         R_Shadow_ClearWorldLights();
3729 }
3730
3731 void R_Shadow_EditLights_Reload_f(void)
3732 {
3733         if (!r_refdef.worldmodel)
3734                 return;
3735         strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3736         R_Shadow_ClearWorldLights();
3737         R_Shadow_LoadWorldLights();
3738         if (r_shadow_worldlightchain == NULL)
3739         {
3740                 R_Shadow_LoadLightsFile();
3741                 if (r_shadow_worldlightchain == NULL)
3742                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3743         }
3744 }
3745
3746 void R_Shadow_EditLights_Save_f(void)
3747 {
3748         if (!r_refdef.worldmodel)
3749                 return;
3750         R_Shadow_SaveWorldLights();
3751 }
3752
3753 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3754 {
3755         R_Shadow_ClearWorldLights();
3756         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3757 }
3758
3759 void R_Shadow_EditLights_ImportLightsFile_f(void)
3760 {
3761         R_Shadow_ClearWorldLights();
3762         R_Shadow_LoadLightsFile();
3763 }
3764
3765 void R_Shadow_EditLights_Spawn_f(void)
3766 {
3767         vec3_t color;
3768         if (!r_editlights.integer)
3769         {
3770                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3771                 return;
3772         }
3773         if (Cmd_Argc() != 1)
3774         {
3775                 Con_Print("r_editlights_spawn does not take parameters\n");
3776                 return;
3777         }
3778         color[0] = color[1] = color[2] = 1;
3779         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3780 }
3781
3782 void R_Shadow_EditLights_Edit_f(void)
3783 {
3784         vec3_t origin, angles, color;
3785         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3786         int style, shadows, flags, normalmode, realtimemode;
3787         char cubemapname[MAX_INPUTLINE];
3788         if (!r_editlights.integer)
3789         {
3790                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3791                 return;
3792         }
3793         if (!r_shadow_selectedlight)
3794         {
3795                 Con_Print("No selected light.\n");
3796                 return;
3797         }
3798         VectorCopy(r_shadow_selectedlight->origin, origin);
3799         VectorCopy(r_shadow_selectedlight->angles, angles);
3800         VectorCopy(r_shadow_selectedlight->color, color);
3801         radius = r_shadow_selectedlight->radius;
3802         style = r_shadow_selectedlight->style;
3803         if (r_shadow_selectedlight->cubemapname)
3804                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3805         else
3806                 cubemapname[0] = 0;
3807         shadows = r_shadow_selectedlight->shadow;
3808         corona = r_shadow_selectedlight->corona;
3809         coronasizescale = r_shadow_selectedlight->coronasizescale;
3810         ambientscale = r_shadow_selectedlight->ambientscale;
3811         diffusescale = r_shadow_selectedlight->diffusescale;
3812         specularscale = r_shadow_selectedlight->specularscale;
3813         flags = r_shadow_selectedlight->flags;
3814         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3815         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3816         if (!strcmp(Cmd_Argv(1), "origin"))
3817         {
3818                 if (Cmd_Argc() != 5)
3819                 {
3820                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3821                         return;
3822                 }
3823                 origin[0] = atof(Cmd_Argv(2));
3824                 origin[1] = atof(Cmd_Argv(3));
3825                 origin[2] = atof(Cmd_Argv(4));
3826         }
3827         else if (!strcmp(Cmd_Argv(1), "originx"))
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[0] = atof(Cmd_Argv(2));
3835         }
3836         else if (!strcmp(Cmd_Argv(1), "originy"))
3837         {
3838                 if (Cmd_Argc() != 3)
3839                 {
3840                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3841                         return;
3842                 }
3843                 origin[1] = atof(Cmd_Argv(2));
3844         }
3845         else if (!strcmp(Cmd_Argv(1), "originz"))
3846         {
3847                 if (Cmd_Argc() != 3)
3848                 {
3849                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3850                         return;
3851                 }
3852                 origin[2] = atof(Cmd_Argv(2));
3853         }
3854         else if (!strcmp(Cmd_Argv(1), "move"))
3855         {
3856                 if (Cmd_Argc() != 5)
3857                 {
3858                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3859                         return;
3860                 }
3861                 origin[0] += atof(Cmd_Argv(2));
3862                 origin[1] += atof(Cmd_Argv(3));
3863                 origin[2] += atof(Cmd_Argv(4));
3864         }
3865         else if (!strcmp(Cmd_Argv(1), "movex"))
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[0] += atof(Cmd_Argv(2));
3873         }
3874         else if (!strcmp(Cmd_Argv(1), "movey"))
3875         {
3876                 if (Cmd_Argc() != 3)
3877                 {
3878                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3879                         return;
3880                 }
3881                 origin[1] += atof(Cmd_Argv(2));
3882         }
3883         else if (!strcmp(Cmd_Argv(1), "movez"))
3884         {
3885                 if (Cmd_Argc() != 3)
3886                 {
3887                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3888                         return;
3889                 }
3890                 origin[2] += atof(Cmd_Argv(2));
3891         }
3892         else if (!strcmp(Cmd_Argv(1), "angles"))
3893         {
3894                 if (Cmd_Argc() != 5)
3895                 {
3896                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3897                         return;
3898                 }
3899                 angles[0] = atof(Cmd_Argv(2));
3900                 angles[1] = atof(Cmd_Argv(3));
3901                 angles[2] = atof(Cmd_Argv(4));
3902         }
3903         else if (!strcmp(Cmd_Argv(1), "anglesx"))
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[0] = atof(Cmd_Argv(2));
3911         }
3912         else if (!strcmp(Cmd_Argv(1), "anglesy"))
3913         {
3914                 if (Cmd_Argc() != 3)
3915                 {
3916                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3917                         return;
3918                 }
3919                 angles[1] = atof(Cmd_Argv(2));
3920         }
3921         else if (!strcmp(Cmd_Argv(1), "anglesz"))
3922         {
3923                 if (Cmd_Argc() != 3)
3924                 {
3925                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3926                         return;
3927                 }
3928                 angles[2] = atof(Cmd_Argv(2));
3929         }
3930         else if (!strcmp(Cmd_Argv(1), "color"))
3931         {
3932                 if (Cmd_Argc() != 5)
3933                 {
3934                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3935                         return;
3936                 }
3937                 color[0] = atof(Cmd_Argv(2));
3938                 color[1] = atof(Cmd_Argv(3));
3939                 color[2] = atof(Cmd_Argv(4));
3940         }
3941         else if (!strcmp(Cmd_Argv(1), "radius"))
3942         {
3943                 if (Cmd_Argc() != 3)
3944                 {
3945                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3946                         return;
3947                 }
3948                 radius = atof(Cmd_Argv(2));
3949         }
3950         else if (!strcmp(Cmd_Argv(1), "colorscale"))
3951         {
3952                 if (Cmd_Argc() == 3)
3953                 {
3954                         double scale = atof(Cmd_Argv(2));
3955                         color[0] *= scale;
3956                         color[1] *= scale;
3957                         color[2] *= scale;
3958                 }
3959                 else
3960                 {
3961                         if (Cmd_Argc() != 5)
3962                         {
3963                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
3964                                 return;
3965                         }
3966                         color[0] *= atof(Cmd_Argv(2));
3967                         color[1] *= atof(Cmd_Argv(3));
3968                         color[2] *= atof(Cmd_Argv(4));
3969                 }
3970         }
3971         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3972         {
3973                 if (Cmd_Argc() != 3)
3974                 {
3975                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3976                         return;
3977                 }
3978                 radius *= atof(Cmd_Argv(2));
3979         }
3980         else if (!strcmp(Cmd_Argv(1), "style"))
3981         {
3982                 if (Cmd_Argc() != 3)
3983                 {
3984                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3985                         return;
3986                 }
3987                 style = atoi(Cmd_Argv(2));
3988         }
3989         else if (!strcmp(Cmd_Argv(1), "cubemap"))
3990         {
3991                 if (Cmd_Argc() > 3)
3992                 {
3993                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3994                         return;
3995                 }
3996                 if (Cmd_Argc() == 3)
3997                         strcpy(cubemapname, Cmd_Argv(2));
3998                 else
3999                         cubemapname[0] = 0;
4000         }
4001         else if (!strcmp(Cmd_Argv(1), "shadows"))
4002         {
4003                 if (Cmd_Argc() != 3)
4004                 {
4005                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4006                         return;
4007                 }
4008                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4009         }
4010         else if (!strcmp(Cmd_Argv(1), "corona"))
4011         {
4012                 if (Cmd_Argc() != 3)
4013                 {
4014                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4015                         return;
4016                 }
4017                 corona = atof(Cmd_Argv(2));
4018         }
4019         else if (!strcmp(Cmd_Argv(1), "coronasize"))
4020         {
4021                 if (Cmd_Argc() != 3)
4022                 {
4023                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4024                         return;
4025                 }
4026                 coronasizescale = atof(Cmd_Argv(2));
4027         }
4028         else if (!strcmp(Cmd_Argv(1), "ambient"))
4029         {
4030                 if (Cmd_Argc() != 3)
4031                 {
4032                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4033                         return;
4034                 }
4035                 ambientscale = atof(Cmd_Argv(2));
4036         }
4037         else if (!strcmp(Cmd_Argv(1), "diffuse"))
4038         {
4039                 if (Cmd_Argc() != 3)
4040                 {
4041                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4042                         return;
4043                 }
4044                 diffusescale = atof(Cmd_Argv(2));
4045         }
4046         else if (!strcmp(Cmd_Argv(1), "specular"))
4047         {
4048                 if (Cmd_Argc() != 3)
4049                 {
4050                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4051                         return;
4052                 }
4053                 specularscale = atof(Cmd_Argv(2));
4054         }
4055         else if (!strcmp(Cmd_Argv(1), "normalmode"))
4056         {
4057                 if (Cmd_Argc() != 3)
4058                 {
4059                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4060                         return;
4061                 }
4062                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4063         }
4064         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4065         {
4066                 if (Cmd_Argc() != 3)
4067                 {
4068                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4069                         return;
4070                 }
4071                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4072         }
4073         else
4074         {
4075                 Con_Print("usage: r_editlights_edit [property] [value]\n");
4076                 Con_Print("Selected light's properties:\n");
4077                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4078                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4079                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4080                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
4081                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
4082                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
4083                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4084                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
4085                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
4086                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
4087                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
4088                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
4089                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4090                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4091                 return;
4092         }
4093         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4094         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4095 }
4096
4097 void R_Shadow_EditLights_EditAll_f(void)
4098 {
4099         dlight_t *light;
4100
4101         if (!r_editlights.integer)
4102         {
4103                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4104                 return;
4105         }
4106
4107         for (light = r_shadow_worldlightchain;light;light = light->next)
4108         {
4109                 R_Shadow_SelectLight(light);
4110                 R_Shadow_EditLights_Edit_f();
4111         }
4112 }
4113
4114 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4115 {
4116         int lightnumber, lightcount;
4117         dlight_t *light;
4118         float x, y;
4119         char temp[256];
4120         if (!r_editlights.integer)
4121                 return;
4122         x = 0;
4123         y = con_vislines;
4124         lightnumber = -1;
4125         lightcount = 0;
4126         for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4127                 if (light == r_shadow_selectedlight)
4128                         lightnumber = lightcount;
4129         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;
4130         if (r_shadow_selectedlight == NULL)
4131                 return;
4132         sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4133         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;
4134         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;
4135         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;
4136         sprintf(temp, "Radius       : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4137         sprintf(temp, "Corona       : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4138         sprintf(temp, "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4139         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;
4140         sprintf(temp, "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4141         sprintf(temp, "CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4142         sprintf(temp, "Ambient      : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4143         sprintf(temp, "Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4144         sprintf(temp, "Specular     : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4145         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;
4146         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;
4147 }
4148
4149 void R_Shadow_EditLights_ToggleShadow_f(void)
4150 {
4151         if (!r_editlights.integer)
4152         {
4153                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
4154                 return;
4155         }
4156         if (!r_shadow_selectedlight)
4157         {
4158                 Con_Print("No selected light.\n");
4159                 return;
4160         }
4161         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
4162 }
4163
4164 void R_Shadow_EditLights_ToggleCorona_f(void)
4165 {
4166         if (!r_editlights.integer)
4167         {
4168                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
4169                 return;
4170         }
4171         if (!r_shadow_selectedlight)
4172         {
4173                 Con_Print("No selected light.\n");
4174                 return;
4175         }
4176         R_Shadow_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);
4177 }
4178
4179 void R_Shadow_EditLights_Remove_f(void)
4180 {
4181         if (!r_editlights.integer)
4182         {
4183                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
4184                 return;
4185         }
4186         if (!r_shadow_selectedlight)
4187         {
4188                 Con_Print("No selected light.\n");
4189                 return;
4190         }
4191         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4192         r_shadow_selectedlight = NULL;
4193 }
4194
4195 void R_Shadow_EditLights_Help_f(void)
4196 {
4197         Con_Print(
4198 "Documentation on r_editlights system:\n"
4199 "Settings:\n"
4200 "r_editlights : enable/disable editing mode\n"
4201 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4202 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4203 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4204 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4205 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4206 "Commands:\n"
4207 "r_editlights_help : this help\n"
4208 "r_editlights_clear : remove all lights\n"
4209 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4210 "r_editlights_save : save to .rtlights file\n"
4211 "r_editlights_spawn : create a light with default settings\n"
4212 "r_editlights_edit command : edit selected light - more documentation below\n"
4213 "r_editlights_remove : remove selected light\n"
4214 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4215 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4216 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4217 "Edit commands:\n"
4218 "origin x y z : set light location\n"
4219 "originx x: set x component of light location\n"
4220 "originy y: set y component of light location\n"
4221 "originz z: set z component of light location\n"
4222 "move x y z : adjust light location\n"
4223 "movex x: adjust x component of light location\n"
4224 "movey y: adjust y component of light location\n"
4225 "movez z: adjust z component of light location\n"
4226 "angles x y z : set light angles\n"
4227 "anglesx x: set x component of light angles\n"
4228 "anglesy y: set y component of light angles\n"
4229 "anglesz z: set z component of light angles\n"
4230 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4231 "radius radius : set radius (size) of light\n"
4232 "colorscale grey : multiply color of light (1 does nothing)\n"
4233 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4234 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4235 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4236 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4237 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4238 "shadows 1/0 : turn on/off shadows\n"
4239 "corona n : set corona intensity\n"
4240 "coronasize n : set corona size (0-1)\n"
4241 "ambient n : set ambient intensity (0-1)\n"
4242 "diffuse n : set diffuse intensity (0-1)\n"
4243 "specular n : set specular intensity (0-1)\n"
4244 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4245 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4246 "<nothing> : print light properties to console\n"
4247         );
4248 }
4249
4250 void R_Shadow_EditLights_CopyInfo_f(void)
4251 {
4252         if (!r_editlights.integer)
4253         {
4254                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
4255                 return;
4256         }
4257         if (!r_shadow_selectedlight)
4258         {
4259                 Con_Print("No selected light.\n");
4260                 return;
4261         }
4262         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4263         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4264         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4265         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4266         if (r_shadow_selectedlight->cubemapname)
4267                 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4268         else
4269                 r_shadow_bufferlight.cubemapname[0] = 0;
4270         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4271         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4272         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4273         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4274         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4275         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4276         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4277 }
4278
4279 void R_Shadow_EditLights_PasteInfo_f(void)
4280 {
4281         if (!r_editlights.integer)
4282         {
4283                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
4284                 return;
4285         }
4286         if (!r_shadow_selectedlight)
4287         {
4288                 Con_Print("No selected light.\n");
4289                 return;
4290         }
4291         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);
4292 }
4293
4294 void R_Shadow_EditLights_Init(void)
4295 {
4296         Cvar_RegisterVariable(&r_editlights);
4297         Cvar_RegisterVariable(&r_editlights_cursordistance);
4298         Cvar_RegisterVariable(&r_editlights_cursorpushback);
4299         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4300         Cvar_RegisterVariable(&r_editlights_cursorgrid);
4301         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4302         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4303         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4304         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)");
4305         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4306         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4307         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4308         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)");
4309         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4310         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4311         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4312         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4313         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4314         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4315         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)");
4316 }
4317