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)
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.
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).
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).
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).
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
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.
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.
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.
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
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).
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.
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
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
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.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
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,
156 r_shadow_rendermode_t;
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;
162 mempool_t *r_shadow_mempool;
164 int maxshadowelements;
178 int r_shadow_buffer_numleafpvsbytes;
179 unsigned char *r_shadow_buffer_leafpvs;
180 int *r_shadow_buffer_leaflist;
182 int r_shadow_buffer_numsurfacepvsbytes;
183 unsigned char *r_shadow_buffer_surfacepvs;
184 int *r_shadow_buffer_surfacelist;
186 rtexturepool_t *r_shadow_texturepool;
187 rtexture_t *r_shadow_attenuation2dtexture;
188 rtexture_t *r_shadow_attenuation3dtexture;
190 // lights are reloaded when this changes
191 char r_shadow_mapname[MAX_QPATH];
193 // used only for light filters (cubemaps)
194 rtexturepool_t *r_shadow_filters_texturepool;
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_glsl = {0, "r_shadow_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
221 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)"};
222 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"};
223 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04", "pushes the effect closer/further"};
224 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)"};
225 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"};
226 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
227 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
228 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
229 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
230 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
231 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
232 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
234 float r_shadow_attenpower, r_shadow_attenscale;
236 rtlight_t *r_shadow_compilingrtlight;
237 dlight_t *r_shadow_worldlightchain;
238 dlight_t *r_shadow_selectedlight;
239 dlight_t r_shadow_bufferlight;
240 vec3_t r_editlights_cursorlocation;
242 extern int con_vislines;
244 typedef struct cubemapinfo_s
251 #define MAX_CUBEMAPS 256
252 static int numcubemaps;
253 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
255 #define SHADERPERMUTATION_COLORMAPPING (1<<0)
256 #define SHADERPERMUTATION_SPECULAR (1<<1)
257 #define SHADERPERMUTATION_FOG (1<<2)
258 #define SHADERPERMUTATION_CUBEFILTER (1<<3)
259 #define SHADERPERMUTATION_OFFSETMAPPING (1<<4)
260 #define SHADERPERMUTATION_SURFACENORMALIZE (1<<5)
261 #define SHADERPERMUTATION_GEFORCEFX (1<<6)
262 #define SHADERPERMUTATION_COUNT (1<<7)
264 // indicates if we have tried compiling this shader permutation yet
265 qboolean r_shadow_program_compiledlight[SHADERPERMUTATION_COUNT];
266 // GLSL program object number, or 0 if compile failed
267 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
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);
280 const char *builtinshader_light_vert =
281 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
282 "// written by Forest 'LordHavoc' Hale\n"
284 "// use half floats if available for math performance\n"
286 "#define myhalf half\n"
287 "#define myhvec2 hvec2\n"
288 "#define myhvec3 hvec3\n"
289 "#define myhvec4 hvec4\n"
291 "#define myhalf float\n"
292 "#define myhvec2 vec2\n"
293 "#define myhvec3 vec3\n"
294 "#define myhvec4 vec4\n"
297 "uniform vec3 LightPosition;\n"
299 "varying vec2 TexCoord;\n"
300 "varying myhvec3 CubeVector;\n"
301 "varying vec3 LightVector;\n"
303 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
304 "uniform vec3 EyePosition;\n"
305 "varying vec3 EyeVector;\n"
308 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
312 " // copy the surface texcoord\n"
313 " TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\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"
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"
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"
335 " // transform vertex to camera space, using ftransform to match non-VS\n"
337 " gl_Position = ftransform();\n"
341 const char *builtinshader_light_frag =
342 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
343 "// written by Forest 'LordHavoc' Hale\n"
345 "// use half floats if available for math performance\n"
347 "#define myhalf half\n"
348 "#define myhvec2 hvec2\n"
349 "#define myhvec3 hvec3\n"
350 "#define myhvec4 hvec4\n"
352 "#define myhalf float\n"
353 "#define myhvec2 vec2\n"
354 "#define myhvec3 vec3\n"
355 "#define myhvec4 vec4\n"
358 "uniform myhvec3 LightColor;\n"
359 "#ifdef USEOFFSETMAPPING\n"
360 "uniform myhalf OffsetMapping_Scale;\n"
361 "uniform myhalf OffsetMapping_Bias;\n"
363 "#ifdef USESPECULAR\n"
364 "uniform myhalf SpecularPower;\n"
367 "uniform myhalf FogRangeRecip;\n"
369 "uniform myhalf AmbientScale;\n"
370 "uniform myhalf DiffuseScale;\n"
371 "#ifdef USESPECULAR\n"
372 "uniform myhalf SpecularScale;\n"
375 "#ifdef USECOLORMAPPING\n"
376 "uniform myhvec3 Color_Pants;\n"
377 "uniform myhvec3 Color_Shirt;\n"
380 "uniform sampler2D Texture_Normal;\n"
381 "uniform sampler2D Texture_Color;\n"
382 "uniform sampler2D Texture_Pants;\n"
383 "uniform sampler2D Texture_Shirt;\n"
384 "#ifdef USESPECULAR\n"
385 "uniform sampler2D Texture_Gloss;\n"
387 "#ifdef USECUBEFILTER\n"
388 "uniform samplerCube Texture_Cube;\n"
391 "uniform sampler2D Texture_FogMask;\n"
394 "varying vec2 TexCoord;\n"
395 "varying myhvec3 CubeVector;\n"
396 "varying vec3 LightVector;\n"
397 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
398 "varying vec3 EyeVector;\n"
405 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
406 " // center and sharp falloff at the edge, this is about the most efficient\n"
407 " // we can get away with as far as providing illumination.\n"
409 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
410 " // provide significant illumination, large = slow = pain.\n"
411 " myhalf colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
415 " colorscale *= texture2D(Texture_FogMask, myhvec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
418 "#ifdef USEOFFSETMAPPING\n"
419 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
420 " myhvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
421 " myhvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
422 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
423 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
424 "#define TexCoord TexCoordOffset\n"
427 " // get the surface normal\n"
428 "#ifdef SURFACENORMALIZE\n"
429 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
431 " myhvec3 surfacenormal = -1.0 + 2.0 * myhvec3(texture2D(Texture_Normal, TexCoord));\n"
434 " // calculate shading\n"
435 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
436 " myhvec4 texturecolor = myhvec4(texture2D(Texture_Color, TexCoord));\n"
437 " colorscale *= texturecolor.a;\n"
438 " myhvec3 color = myhvec3(texturecolor);\n"
439 "#ifdef USECOLORMAPPING\n"
440 " color += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
442 " color *= (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
443 "#ifdef USESPECULAR\n"
444 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
445 " color += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
448 "#ifdef USECUBEFILTER\n"
449 " // apply light cubemap filter\n"
450 " color *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
453 " // calculate fragment color (apply light color and attenuation/fog scaling)\n"
454 " gl_FragColor = myhvec4(color * LightColor * colorscale, 1);\n"
458 int R_Shadow_CompileShaderPermutation(int permutation)
460 char *vertstring, *fragstring;
461 int vertstrings_count;
462 int fragstrings_count;
463 const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
464 const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
465 char permutationname[256];
466 if (r_shadow_program_compiledlight[permutation])
467 return r_shadow_program_light[permutation];
468 r_shadow_program_compiledlight[permutation] = true;
469 vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false, NULL);
470 fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false, NULL);
471 vertstrings_count = 0;
472 fragstrings_count = 0;
473 permutationname[0] = 0;
474 if (permutation & SHADERPERMUTATION_COLORMAPPING)
476 vertstrings_list[vertstrings_count++] = "#define USECOLORMAPPING\n";
477 fragstrings_list[fragstrings_count++] = "#define USECOLORMAPPING\n";
478 strlcat(permutationname, " colormapping", sizeof(permutationname));
480 if (permutation & SHADERPERMUTATION_SPECULAR)
482 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
483 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
484 strlcat(permutationname, " specular", sizeof(permutationname));
486 if (permutation & SHADERPERMUTATION_FOG)
488 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
489 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
490 strlcat(permutationname, " fog", sizeof(permutationname));
492 if (permutation & SHADERPERMUTATION_CUBEFILTER)
494 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
495 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
496 strlcat(permutationname, " cubefilter", sizeof(permutationname));
498 if (permutation & SHADERPERMUTATION_OFFSETMAPPING)
500 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
501 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
502 strlcat(permutationname, " offsetmapping", sizeof(permutationname));
504 if (permutation & SHADERPERMUTATION_SURFACENORMALIZE)
506 vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
507 fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
508 strlcat(permutationname, " surfacenormalize", sizeof(permutationname));
510 if (permutation & SHADERPERMUTATION_GEFORCEFX)
512 vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
513 fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
514 strlcat(permutationname, " halffloat", sizeof(permutationname));
516 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
517 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
518 r_shadow_program_light[permutation] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
519 if (r_shadow_program_light[permutation])
521 qglUseProgramObjectARB(r_shadow_program_light[permutation]);
522 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Normal"), 0);CHECKGLERROR
523 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Color"), 1);CHECKGLERROR
524 if (permutation & SHADERPERMUTATION_SPECULAR)
526 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Gloss"), 2);CHECKGLERROR
528 if (permutation & SHADERPERMUTATION_CUBEFILTER)
530 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Cube"), 3);CHECKGLERROR
532 if (permutation & SHADERPERMUTATION_FOG)
534 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_FogMask"), 4);CHECKGLERROR
536 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Pants"), 5);CHECKGLERROR
537 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Shirt"), 6);CHECKGLERROR
538 qglUseProgramObjectARB(0);
541 Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, "glsl/light");
543 Mem_Free(fragstring);
545 Mem_Free(vertstring);
546 return r_shadow_program_light[permutation];
549 void r_shadow_start(void)
552 // use half float math where available (speed gain on NVIDIA GFFX and GF6)
553 if (gl_support_half_float)
554 Cvar_SetValue("r_shadow_glsl_usehalffloat", 1);
555 // allocate vertex processing arrays
557 r_shadow_attenuation2dtexture = NULL;
558 r_shadow_attenuation3dtexture = NULL;
559 r_shadow_texturepool = NULL;
560 r_shadow_filters_texturepool = NULL;
561 R_Shadow_ValidateCvars();
562 R_Shadow_MakeTextures();
563 maxshadowelements = 0;
564 shadowelements = NULL;
572 shadowmarklist = NULL;
574 r_shadow_buffer_numleafpvsbytes = 0;
575 r_shadow_buffer_leafpvs = NULL;
576 r_shadow_buffer_leaflist = NULL;
577 r_shadow_buffer_numsurfacepvsbytes = 0;
578 r_shadow_buffer_surfacepvs = NULL;
579 r_shadow_buffer_surfacelist = NULL;
580 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
582 r_shadow_program_compiledlight[i] = false;
583 r_shadow_program_light[i] = 0;
587 void r_shadow_shutdown(void)
590 R_Shadow_UncompileWorldLights();
591 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
593 if (r_shadow_program_light[i])
595 GL_Backend_FreeProgram(r_shadow_program_light[i]);
596 r_shadow_program_light[i] = 0;
600 r_shadow_attenuation2dtexture = NULL;
601 r_shadow_attenuation3dtexture = NULL;
602 R_FreeTexturePool(&r_shadow_texturepool);
603 R_FreeTexturePool(&r_shadow_filters_texturepool);
604 maxshadowelements = 0;
606 Mem_Free(shadowelements);
607 shadowelements = NULL;
610 Mem_Free(vertexupdate);
613 Mem_Free(vertexremap);
619 Mem_Free(shadowmark);
622 Mem_Free(shadowmarklist);
623 shadowmarklist = NULL;
625 r_shadow_buffer_numleafpvsbytes = 0;
626 if (r_shadow_buffer_leafpvs)
627 Mem_Free(r_shadow_buffer_leafpvs);
628 r_shadow_buffer_leafpvs = NULL;
629 if (r_shadow_buffer_leaflist)
630 Mem_Free(r_shadow_buffer_leaflist);
631 r_shadow_buffer_leaflist = NULL;
632 r_shadow_buffer_numsurfacepvsbytes = 0;
633 if (r_shadow_buffer_surfacepvs)
634 Mem_Free(r_shadow_buffer_surfacepvs);
635 r_shadow_buffer_surfacepvs = NULL;
636 if (r_shadow_buffer_surfacelist)
637 Mem_Free(r_shadow_buffer_surfacelist);
638 r_shadow_buffer_surfacelist = NULL;
641 void r_shadow_newmap(void)
645 void R_Shadow_Help_f(void)
648 "Documentation on r_shadow system:\n"
650 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
651 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
652 "r_shadow_debuglight : render only this light number (-1 = all)\n"
653 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
654 "r_shadow_gloss2intensity : brightness of forced gloss\n"
655 "r_shadow_glossintensity : brightness of textured gloss\n"
656 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
657 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
658 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
659 "r_shadow_portallight : use portal visibility for static light precomputation\n"
660 "r_shadow_projectdistance : shadow volume projection distance\n"
661 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
662 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
663 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
664 "r_shadow_realtime_world : use high quality world lighting mode\n"
665 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
666 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
667 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
668 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
669 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
670 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
671 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
672 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
673 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
674 "r_shadow_glsl_usehalffloat : use lower quality lighting\n"
675 "r_shadow_glsl_surfacenormalize : makes bumpmapping slightly higher quality\n"
676 "r_shadow_scissor : use scissor optimization\n"
677 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
678 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
679 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
680 "r_showlighting : useful for performance testing; bright = slow!\n"
681 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
683 "r_shadow_help : this help\n"
687 void R_Shadow_Init(void)
689 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
690 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
691 Cvar_RegisterVariable(&r_shadow_debuglight);
692 Cvar_RegisterVariable(&r_shadow_gloss);
693 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
694 Cvar_RegisterVariable(&r_shadow_glossintensity);
695 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
696 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
697 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
698 Cvar_RegisterVariable(&r_shadow_portallight);
699 Cvar_RegisterVariable(&r_shadow_projectdistance);
700 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
701 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
702 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
703 Cvar_RegisterVariable(&r_shadow_realtime_world);
704 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
705 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
706 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
707 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
708 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
709 Cvar_RegisterVariable(&r_shadow_scissor);
710 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
711 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
712 Cvar_RegisterVariable(&r_shadow_texture3d);
713 Cvar_RegisterVariable(&r_shadow_glsl);
714 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
715 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
716 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
717 Cvar_RegisterVariable(&r_shadow_glsl_usehalffloat);
718 Cvar_RegisterVariable(&r_shadow_glsl_surfacenormalize);
719 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
720 if (gamemode == GAME_TENEBRAE)
722 Cvar_SetValue("r_shadow_gloss", 2);
723 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
725 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
726 R_Shadow_EditLights_Init();
727 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
728 r_shadow_worldlightchain = NULL;
729 maxshadowelements = 0;
730 shadowelements = NULL;
738 shadowmarklist = NULL;
740 r_shadow_buffer_numleafpvsbytes = 0;
741 r_shadow_buffer_leafpvs = NULL;
742 r_shadow_buffer_leaflist = NULL;
743 r_shadow_buffer_numsurfacepvsbytes = 0;
744 r_shadow_buffer_surfacepvs = NULL;
745 r_shadow_buffer_surfacelist = NULL;
746 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
749 matrix4x4_t matrix_attenuationxyz =
752 {0.5, 0.0, 0.0, 0.5},
753 {0.0, 0.5, 0.0, 0.5},
754 {0.0, 0.0, 0.5, 0.5},
759 matrix4x4_t matrix_attenuationz =
762 {0.0, 0.0, 0.5, 0.5},
763 {0.0, 0.0, 0.0, 0.5},
764 {0.0, 0.0, 0.0, 0.5},
769 int *R_Shadow_ResizeShadowElements(int numtris)
771 // make sure shadowelements is big enough for this volume
772 if (maxshadowelements < numtris * 24)
774 maxshadowelements = numtris * 24;
776 Mem_Free(shadowelements);
777 shadowelements = (int *)Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
779 return shadowelements;
782 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
784 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
785 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
786 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
788 if (r_shadow_buffer_leafpvs)
789 Mem_Free(r_shadow_buffer_leafpvs);
790 if (r_shadow_buffer_leaflist)
791 Mem_Free(r_shadow_buffer_leaflist);
792 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
793 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
794 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
796 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
798 if (r_shadow_buffer_surfacepvs)
799 Mem_Free(r_shadow_buffer_surfacepvs);
800 if (r_shadow_buffer_surfacelist)
801 Mem_Free(r_shadow_buffer_surfacelist);
802 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
803 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
804 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
808 void R_Shadow_PrepareShadowMark(int numtris)
810 // make sure shadowmark is big enough for this volume
811 if (maxshadowmark < numtris)
813 maxshadowmark = numtris;
815 Mem_Free(shadowmark);
817 Mem_Free(shadowmarklist);
818 shadowmark = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
819 shadowmarklist = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
823 // if shadowmarkcount wrapped we clear the array and adjust accordingly
824 if (shadowmarkcount == 0)
827 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
832 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)
835 int outtriangles = 0, outvertices = 0;
839 if (maxvertexupdate < innumvertices)
841 maxvertexupdate = innumvertices;
843 Mem_Free(vertexupdate);
845 Mem_Free(vertexremap);
846 vertexupdate = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
847 vertexremap = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
851 if (vertexupdatenum == 0)
854 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
855 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
858 for (i = 0;i < numshadowmarktris;i++)
859 shadowmark[shadowmarktris[i]] = shadowmarkcount;
861 for (i = 0;i < numshadowmarktris;i++)
863 element = inelement3i + shadowmarktris[i] * 3;
864 // make sure the vertices are created
865 for (j = 0;j < 3;j++)
867 if (vertexupdate[element[j]] != vertexupdatenum)
869 float ratio, direction[3];
870 vertexupdate[element[j]] = vertexupdatenum;
871 vertexremap[element[j]] = outvertices;
872 vertex = invertex3f + element[j] * 3;
873 // project one copy of the vertex to the sphere radius of the light
874 // (FIXME: would projecting it to the light box be better?)
875 VectorSubtract(vertex, projectorigin, direction);
876 ratio = projectdistance / VectorLength(direction);
877 VectorCopy(vertex, outvertex3f);
878 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
885 for (i = 0;i < numshadowmarktris;i++)
887 int remappedelement[3];
889 const int *neighbortriangle;
891 markindex = shadowmarktris[i] * 3;
892 element = inelement3i + markindex;
893 neighbortriangle = inneighbor3i + markindex;
894 // output the front and back triangles
895 outelement3i[0] = vertexremap[element[0]];
896 outelement3i[1] = vertexremap[element[1]];
897 outelement3i[2] = vertexremap[element[2]];
898 outelement3i[3] = vertexremap[element[2]] + 1;
899 outelement3i[4] = vertexremap[element[1]] + 1;
900 outelement3i[5] = vertexremap[element[0]] + 1;
904 // output the sides (facing outward from this triangle)
905 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
907 remappedelement[0] = vertexremap[element[0]];
908 remappedelement[1] = vertexremap[element[1]];
909 outelement3i[0] = remappedelement[1];
910 outelement3i[1] = remappedelement[0];
911 outelement3i[2] = remappedelement[0] + 1;
912 outelement3i[3] = remappedelement[1];
913 outelement3i[4] = remappedelement[0] + 1;
914 outelement3i[5] = remappedelement[1] + 1;
919 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
921 remappedelement[1] = vertexremap[element[1]];
922 remappedelement[2] = vertexremap[element[2]];
923 outelement3i[0] = remappedelement[2];
924 outelement3i[1] = remappedelement[1];
925 outelement3i[2] = remappedelement[1] + 1;
926 outelement3i[3] = remappedelement[2];
927 outelement3i[4] = remappedelement[1] + 1;
928 outelement3i[5] = remappedelement[2] + 1;
933 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
935 remappedelement[0] = vertexremap[element[0]];
936 remappedelement[2] = vertexremap[element[2]];
937 outelement3i[0] = remappedelement[0];
938 outelement3i[1] = remappedelement[2];
939 outelement3i[2] = remappedelement[2] + 1;
940 outelement3i[3] = remappedelement[0];
941 outelement3i[4] = remappedelement[2] + 1;
942 outelement3i[5] = remappedelement[0] + 1;
949 *outnumvertices = outvertices;
953 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)
956 if (projectdistance < 0.1)
958 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
961 if (!numverts || !nummarktris)
963 // make sure shadowelements is big enough for this volume
964 if (maxshadowelements < nummarktris * 24)
965 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
966 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
967 renderstats.lights_dynamicshadowtriangles += tris;
968 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
971 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)
976 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
978 tend = firsttriangle + numtris;
979 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
980 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
981 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
983 // surface box entirely inside light box, no box cull
984 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
985 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
986 shadowmarklist[numshadowmark++] = t;
990 // surface box not entirely inside light box, cull each triangle
991 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
993 v[0] = invertex3f + e[0] * 3;
994 v[1] = invertex3f + e[1] * 3;
995 v[2] = invertex3f + e[2] * 3;
996 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
997 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
998 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
999 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
1000 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
1001 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
1002 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
1003 shadowmarklist[numshadowmark++] = t;
1008 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
1011 if (r_shadow_compilingrtlight)
1013 // if we're compiling an rtlight, capture the mesh
1014 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
1017 renderstats.lights_shadowtriangles += numtriangles;
1018 memset(&m, 0, sizeof(m));
1019 m.pointer_vertex = vertex3f;
1021 GL_LockArrays(0, numvertices);
1022 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
1024 // decrement stencil if backface is behind depthbuffer
1025 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
1026 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1027 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
1028 // increment stencil if frontface is behind depthbuffer
1029 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1030 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1032 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
1033 GL_LockArrays(0, 0);
1036 static void R_Shadow_MakeTextures(void)
1039 float v[3], intensity;
1040 unsigned char *data;
1041 R_FreeTexturePool(&r_shadow_texturepool);
1042 r_shadow_texturepool = R_AllocTexturePool();
1043 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
1044 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
1045 #define ATTEN2DSIZE 64
1046 #define ATTEN3DSIZE 32
1047 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
1048 for (y = 0;y < ATTEN2DSIZE;y++)
1050 for (x = 0;x < ATTEN2DSIZE;x++)
1052 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1053 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1055 intensity = 1.0f - sqrt(DotProduct(v, v));
1057 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1058 d = bound(0, intensity, 255);
1059 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1060 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1061 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1062 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1065 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1066 if (r_shadow_texture3d.integer)
1068 for (z = 0;z < ATTEN3DSIZE;z++)
1070 for (y = 0;y < ATTEN3DSIZE;y++)
1072 for (x = 0;x < ATTEN3DSIZE;x++)
1074 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1075 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1076 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1077 intensity = 1.0f - sqrt(DotProduct(v, v));
1079 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1080 d = bound(0, intensity, 255);
1081 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1082 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1083 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1084 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1088 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1093 void R_Shadow_ValidateCvars(void)
1095 if (r_shadow_texture3d.integer && !gl_texture3d)
1096 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1097 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1098 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1101 // light currently being rendered
1102 rtlight_t *r_shadow_rtlight;
1104 // this is the location of the eye in entity space
1105 vec3_t r_shadow_entityeyeorigin;
1106 // this is the location of the light in entity space
1107 vec3_t r_shadow_entitylightorigin;
1108 // this transforms entity coordinates to light filter cubemap coordinates
1109 // (also often used for other purposes)
1110 matrix4x4_t r_shadow_entitytolight;
1111 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1112 // of attenuation texturing in full 3D (Z result often ignored)
1113 matrix4x4_t r_shadow_entitytoattenuationxyz;
1114 // this transforms only the Z to S, and T is always 0.5
1115 matrix4x4_t r_shadow_entitytoattenuationz;
1117 static int r_shadow_lightpermutation;
1118 static int r_shadow_lightprog;
1120 void R_Shadow_RenderMode_Begin(void)
1124 R_Shadow_ValidateCvars();
1126 if (!r_shadow_attenuation2dtexture
1127 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1128 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1129 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1130 R_Shadow_MakeTextures();
1132 memset(&m, 0, sizeof(m));
1134 GL_BlendFunc(GL_ONE, GL_ZERO);
1135 GL_DepthMask(false);
1137 GL_Color(0, 0, 0, 1);
1138 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1139 qglEnable(GL_CULL_FACE);
1140 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1142 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1144 if (gl_ext_stenciltwoside.integer)
1145 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1147 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1149 if (r_shadow_glsl.integer && gl_support_fragment_shader)
1150 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1151 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1152 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1154 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1157 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1159 r_shadow_rtlight = rtlight;
1162 void R_Shadow_RenderMode_Reset(void)
1165 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1167 qglUseProgramObjectARB(0);
1168 // HACK HACK HACK: work around for bug in NVIDIAI 6xxx drivers that causes GL_OUT_OF_MEMORY and/or software rendering
1169 qglBegin(GL_TRIANGLES);
1173 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1174 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1175 memset(&m, 0, sizeof(m));
1179 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1181 R_Shadow_RenderMode_Reset();
1182 GL_Color(1, 1, 1, 1);
1183 GL_ColorMask(0, 0, 0, 0);
1184 GL_BlendFunc(GL_ONE, GL_ZERO);
1185 GL_DepthMask(false);
1187 if (!r_showtrispass)
1188 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1189 //if (r_shadow_shadow_polygonoffset.value != 0)
1191 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1192 // qglEnable(GL_POLYGON_OFFSET_FILL);
1195 // qglDisable(GL_POLYGON_OFFSET_FILL);
1196 qglDepthFunc(GL_LESS);
1197 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1198 qglEnable(GL_STENCIL_TEST);
1199 qglStencilFunc(GL_ALWAYS, 128, ~0);
1200 r_shadow_rendermode = r_shadow_shadowingrendermode;
1201 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1203 qglDisable(GL_CULL_FACE);
1204 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1205 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1207 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1208 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1210 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1214 qglEnable(GL_CULL_FACE);
1216 // this is changed by every shadow render so its value here is unimportant
1217 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1219 GL_Clear(GL_STENCIL_BUFFER_BIT);
1220 renderstats.lights_clears++;
1223 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1225 R_Shadow_RenderMode_Reset();
1226 GL_BlendFunc(GL_ONE, GL_ONE);
1227 GL_DepthMask(false);
1229 if (!r_showtrispass)
1230 qglPolygonOffset(0, 0);
1231 //qglDisable(GL_POLYGON_OFFSET_FILL);
1232 GL_Color(1, 1, 1, 1);
1233 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1235 qglDepthFunc(GL_LEQUAL);
1237 qglDepthFunc(GL_EQUAL);
1238 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1239 qglEnable(GL_CULL_FACE);
1241 qglEnable(GL_STENCIL_TEST);
1243 qglDisable(GL_STENCIL_TEST);
1245 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1246 // only draw light where this geometry was already rendered AND the
1247 // stencil is 128 (values other than this mean shadow)
1248 qglStencilFunc(GL_EQUAL, 128, ~0);
1249 r_shadow_rendermode = r_shadow_lightingrendermode;
1250 // do global setup needed for the chosen lighting mode
1251 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1253 R_Mesh_VertexPointer(varray_vertex3f);
1254 R_Mesh_TexCoordPointer(0, 2, varray_texcoord2f[0]);
1255 R_Mesh_TexCoordPointer(1, 3, varray_svector3f);
1256 R_Mesh_TexCoordPointer(2, 3, varray_tvector3f);
1257 R_Mesh_TexCoordPointer(3, 3, varray_normal3f);
1258 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1259 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1260 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1261 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1262 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1263 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1264 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1265 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1266 GL_BlendFunc(GL_ONE, GL_ONE);
1267 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1272 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1274 R_Shadow_RenderMode_Reset();
1275 GL_BlendFunc(GL_ONE, GL_ONE);
1276 GL_DepthMask(false);
1277 GL_DepthTest(!r_showdisabledepthtest.integer);
1278 if (!r_showtrispass)
1279 qglPolygonOffset(0, 0);
1280 GL_Color(0.0, 0.0125, 0.1, 1);
1281 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1282 qglDepthFunc(GL_GEQUAL);
1283 qglCullFace(GL_FRONT); // this culls back
1284 qglDisable(GL_CULL_FACE);
1285 qglDisable(GL_STENCIL_TEST);
1286 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1289 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1291 R_Shadow_RenderMode_Reset();
1292 GL_BlendFunc(GL_ONE, GL_ONE);
1293 GL_DepthMask(false);
1294 GL_DepthTest(!r_showdisabledepthtest.integer);
1295 if (!r_showtrispass)
1296 qglPolygonOffset(0, 0);
1297 GL_Color(0.1, 0.0125, 0, 1);
1298 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1300 qglDepthFunc(GL_LEQUAL);
1302 qglDepthFunc(GL_EQUAL);
1303 qglCullFace(GL_FRONT); // this culls back
1304 qglEnable(GL_CULL_FACE);
1306 qglEnable(GL_STENCIL_TEST);
1308 qglDisable(GL_STENCIL_TEST);
1309 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1312 void R_Shadow_RenderMode_End(void)
1314 R_Shadow_RenderMode_Reset();
1315 R_Shadow_RenderMode_ActiveLight(NULL);
1316 GL_BlendFunc(GL_ONE, GL_ZERO);
1319 if (!r_showtrispass)
1320 qglPolygonOffset(0, 0);
1321 //qglDisable(GL_POLYGON_OFFSET_FILL);
1322 GL_Color(1, 1, 1, 1);
1323 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1324 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1325 qglDepthFunc(GL_LEQUAL);
1326 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1327 qglEnable(GL_CULL_FACE);
1328 qglDisable(GL_STENCIL_TEST);
1329 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1330 if (gl_support_stenciltwoside)
1331 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1333 qglStencilFunc(GL_ALWAYS, 128, ~0);
1334 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1337 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1339 int i, ix1, iy1, ix2, iy2;
1340 float x1, y1, x2, y2;
1343 mplane_t planes[11];
1344 float vertex3f[256*3];
1346 // if view is inside the light box, just say yes it's visible
1347 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1349 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1353 // create a temporary brush describing the area the light can affect in worldspace
1354 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1355 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1356 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1357 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1358 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1359 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1360 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1361 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1362 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1363 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1364 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1366 // turn the brush into a mesh
1367 memset(&mesh, 0, sizeof(rmesh_t));
1368 mesh.maxvertices = 256;
1369 mesh.vertex3f = vertex3f;
1370 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1371 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1373 // if that mesh is empty, the light is not visible at all
1374 if (!mesh.numvertices)
1377 if (!r_shadow_scissor.integer)
1380 // if that mesh is not empty, check what area of the screen it covers
1381 x1 = y1 = x2 = y2 = 0;
1383 for (i = 0;i < mesh.numvertices;i++)
1385 VectorCopy(mesh.vertex3f + i * 3, v);
1386 GL_TransformToScreen(v, v2);
1387 //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]);
1390 if (x1 > v2[0]) x1 = v2[0];
1391 if (x2 < v2[0]) x2 = v2[0];
1392 if (y1 > v2[1]) y1 = v2[1];
1393 if (y2 < v2[1]) y2 = v2[1];
1402 // now convert the scissor rectangle to integer screen coordinates
1407 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1409 // clamp it to the screen
1410 if (ix1 < r_view_x) ix1 = r_view_x;
1411 if (iy1 < r_view_y) iy1 = r_view_y;
1412 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1413 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1415 // if it is inside out, it's not visible
1416 if (ix2 <= ix1 || iy2 <= iy1)
1419 // the light area is visible, set up the scissor rectangle
1420 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1421 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1422 //qglEnable(GL_SCISSOR_TEST);
1423 renderstats.lights_scissored++;
1427 extern float *rsurface_vertex3f;
1428 extern float *rsurface_svector3f;
1429 extern float *rsurface_tvector3f;
1430 extern float *rsurface_normal3f;
1431 extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
1433 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1435 int numverts = surface->num_vertices;
1436 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1437 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1438 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1439 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1440 if (r_textureunits.integer >= 3)
1442 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1444 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1445 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1446 if ((dot = DotProduct(n, v)) < 0)
1448 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1449 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1450 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1451 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1454 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1455 VectorScale(color4f, f, color4f);
1459 VectorClear(color4f);
1463 else if (r_textureunits.integer >= 2)
1465 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1467 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1468 if ((dist = fabs(v[2])) < 1)
1470 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1471 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1472 if ((dot = DotProduct(n, v)) < 0)
1474 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1475 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1476 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1477 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1481 color4f[0] = ambientcolor[0] * distintensity;
1482 color4f[1] = ambientcolor[1] * distintensity;
1483 color4f[2] = ambientcolor[2] * distintensity;
1487 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1488 VectorScale(color4f, f, color4f);
1492 VectorClear(color4f);
1498 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1500 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1501 if ((dist = DotProduct(v, v)) < 1)
1504 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1505 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1506 if ((dot = DotProduct(n, v)) < 0)
1508 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1509 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1510 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1511 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1515 color4f[0] = ambientcolor[0] * distintensity;
1516 color4f[1] = ambientcolor[1] * distintensity;
1517 color4f[2] = ambientcolor[2] * distintensity;
1521 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1522 VectorScale(color4f, f, color4f);
1526 VectorClear(color4f);
1532 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1533 #define USETEXMATRIX
1535 #ifndef USETEXMATRIX
1536 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1537 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1538 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1542 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1543 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1544 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1551 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1555 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1556 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1564 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)
1568 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1570 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1571 // the cubemap normalizes this for us
1572 out3f[0] = DotProduct(svector3f, lightdir);
1573 out3f[1] = DotProduct(tvector3f, lightdir);
1574 out3f[2] = DotProduct(normal3f, lightdir);
1578 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)
1581 float lightdir[3], eyedir[3], halfdir[3];
1582 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1584 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1585 VectorNormalize(lightdir);
1586 VectorSubtract(relativeeyeorigin, vertex3f, eyedir);
1587 VectorNormalize(eyedir);
1588 VectorAdd(lightdir, eyedir, halfdir);
1589 // the cubemap normalizes this for us
1590 out3f[0] = DotProduct(svector3f, halfdir);
1591 out3f[1] = DotProduct(tvector3f, halfdir);
1592 out3f[2] = DotProduct(normal3f, halfdir);
1596 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, qboolean dopants, qboolean doshirt)
1598 // used to display how many times a surface is lit for level design purposes
1599 int surfacelistindex;
1601 GL_Color(0.1, 0.025, 0, 1);
1602 memset(&m, 0, sizeof(m));
1604 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1606 const msurface_t *surface = surfacelist[surfacelistindex];
1607 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
1608 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1609 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
1610 GL_LockArrays(0, 0);
1614 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, qboolean dopants, qboolean doshirt)
1616 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1617 int surfacelistindex;
1618 // select a permutation of the lighting shader appropriate to this
1619 // combination of texture, entity, light source, and fogging, only use the
1620 // minimum features necessary to avoid wasting rendering time in the
1621 // fragment shader on features that are not being used
1622 r_shadow_lightpermutation = 0;
1624 r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1625 if ((dopants || doshirt))
1626 r_shadow_lightpermutation |= SHADERPERMUTATION_COLORMAPPING;
1627 if (specularscale > 0)
1628 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1629 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1630 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1631 if (r_shadow_glsl_offsetmapping.integer)
1632 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1633 if (r_shadow_glsl_surfacenormalize.integer)
1634 r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
1635 if (r_shadow_glsl_usehalffloat.integer)
1636 r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
1637 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1638 if (!r_shadow_lightprog)
1640 if (!r_shadow_program_compiledlight[r_shadow_lightpermutation])
1641 r_shadow_lightprog = R_Shadow_CompileShaderPermutation(r_shadow_lightpermutation);
1642 if (!r_shadow_lightprog)
1644 // remove features until we find a valid permutation
1646 for (i = SHADERPERMUTATION_COUNT-1;;i>>=1)
1648 // reduce i more quickly whenever it would not remove any bits
1649 if (r_shadow_lightpermutation < i)
1651 r_shadow_lightpermutation &= i;
1652 if (!r_shadow_program_compiledlight[r_shadow_lightpermutation])
1653 R_Shadow_CompileShaderPermutation(r_shadow_lightpermutation);
1654 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1655 if (r_shadow_lightprog)
1658 return; // utterly failed
1662 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1663 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
1664 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
1665 R_Mesh_TexBind(0, R_GetTexture(normalmaptexture));
1666 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1667 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
1668 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1670 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
1672 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1673 if (r_shadow_lightpermutation & SHADERPERMUTATION_COLORMAPPING)
1675 R_Mesh_TexBind(5, R_GetTexture(pantstexture));
1676 R_Mesh_TexBind(6, R_GetTexture(shirttexture));
1677 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "Color_Pants"), ent->colormap_pantscolor[0], ent->colormap_pantscolor[1], ent->colormap_pantscolor[2]);CHECKGLERROR
1678 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "Color_Shirt"), ent->colormap_shirtcolor[0], ent->colormap_shirtcolor[1], ent->colormap_shirtcolor[2]);CHECKGLERROR
1680 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1682 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), fograngerecip);CHECKGLERROR
1684 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1685 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1686 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1688 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1689 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1690 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1692 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1694 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1695 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1697 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1699 const msurface_t *surface = surfacelist[surfacelistindex];
1700 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1701 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
1702 if (!rsurface_svector3f)
1704 rsurface_svector3f = varray_svector3f;
1705 rsurface_tvector3f = varray_tvector3f;
1706 rsurface_normal3f = varray_normal3f;
1707 Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
1709 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1710 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1711 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1712 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1713 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1714 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1715 GL_LockArrays(0, 0);
1719 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1724 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1726 // colorscale accounts for how much we multiply the brightness
1729 // mult is how many times the final pass of the lighting will be
1730 // performed to get more brightness than otherwise possible.
1732 // Limit mult to 64 for sanity sake.
1733 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1735 // 3 3D combine path (Geforce3, Radeon 8500)
1736 memset(&m, 0, sizeof(m));
1737 m.pointer_vertex = rsurface_vertex3f;
1738 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1740 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1741 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1743 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1744 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1746 m.tex[1] = R_GetTexture(basetexture);
1747 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1748 m.texmatrix[1] = texture->currenttexmatrix;
1749 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1751 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1752 m.texmatrix[2] = r_shadow_entitytolight;
1754 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1755 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1757 GL_BlendFunc(GL_ONE, GL_ONE);
1759 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1761 // 2 3D combine path (Geforce3, original Radeon)
1762 memset(&m, 0, sizeof(m));
1763 m.pointer_vertex = rsurface_vertex3f;
1764 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1766 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1767 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1769 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1770 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1772 m.tex[1] = R_GetTexture(basetexture);
1773 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1774 m.texmatrix[1] = texture->currenttexmatrix;
1775 GL_BlendFunc(GL_ONE, GL_ONE);
1777 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1779 // 4 2D combine path (Geforce3, Radeon 8500)
1780 memset(&m, 0, sizeof(m));
1781 m.pointer_vertex = rsurface_vertex3f;
1782 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1784 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1785 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1787 m.pointer_texcoord[0] = varray_texcoord2f[0];
1788 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1790 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1792 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1793 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1795 m.pointer_texcoord[1] = varray_texcoord2f[1];
1796 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1798 m.tex[2] = R_GetTexture(basetexture);
1799 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1800 m.texmatrix[2] = texture->currenttexmatrix;
1801 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1803 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1805 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1806 m.texmatrix[3] = r_shadow_entitytolight;
1808 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1809 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1812 GL_BlendFunc(GL_ONE, GL_ONE);
1814 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1816 // 3 2D combine path (Geforce3, original Radeon)
1817 memset(&m, 0, sizeof(m));
1818 m.pointer_vertex = rsurface_vertex3f;
1819 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1821 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1822 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1824 m.pointer_texcoord[0] = varray_texcoord2f[0];
1825 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1827 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1829 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1830 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1832 m.pointer_texcoord[1] = varray_texcoord2f[1];
1833 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1835 m.tex[2] = R_GetTexture(basetexture);
1836 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1837 m.texmatrix[2] = texture->currenttexmatrix;
1838 GL_BlendFunc(GL_ONE, GL_ONE);
1842 // 2/2/2 2D combine path (any dot3 card)
1843 memset(&m, 0, sizeof(m));
1844 m.pointer_vertex = rsurface_vertex3f;
1845 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1847 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1848 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1850 m.pointer_texcoord[0] = varray_texcoord2f[0];
1851 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1853 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1855 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1856 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1858 m.pointer_texcoord[1] = varray_texcoord2f[1];
1859 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1862 GL_ColorMask(0,0,0,1);
1863 GL_BlendFunc(GL_ONE, GL_ZERO);
1864 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1865 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1866 GL_LockArrays(0, 0);
1868 memset(&m, 0, sizeof(m));
1869 m.pointer_vertex = rsurface_vertex3f;
1870 m.tex[0] = R_GetTexture(basetexture);
1871 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1872 m.texmatrix[0] = texture->currenttexmatrix;
1873 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1875 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1877 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1878 m.texmatrix[1] = r_shadow_entitytolight;
1880 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1881 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1884 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1886 // this final code is shared
1888 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1889 VectorScale(lightcolorbase, colorscale, color2);
1890 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1891 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1893 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1894 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1896 GL_LockArrays(0, 0);
1899 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1904 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1906 // colorscale accounts for how much we multiply the brightness
1909 // mult is how many times the final pass of the lighting will be
1910 // performed to get more brightness than otherwise possible.
1912 // Limit mult to 64 for sanity sake.
1913 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1915 // 3/2 3D combine path (Geforce3, Radeon 8500)
1916 memset(&m, 0, sizeof(m));
1917 m.pointer_vertex = rsurface_vertex3f;
1918 m.tex[0] = R_GetTexture(normalmaptexture);
1919 m.texcombinergb[0] = GL_REPLACE;
1920 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1921 m.texmatrix[0] = texture->currenttexmatrix;
1922 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1923 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1924 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1925 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);
1926 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1928 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1929 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1931 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1932 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1935 GL_ColorMask(0,0,0,1);
1936 GL_BlendFunc(GL_ONE, GL_ZERO);
1937 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1938 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1939 GL_LockArrays(0, 0);
1941 memset(&m, 0, sizeof(m));
1942 m.pointer_vertex = rsurface_vertex3f;
1943 m.tex[0] = R_GetTexture(basetexture);
1944 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1945 m.texmatrix[0] = texture->currenttexmatrix;
1946 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1948 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1950 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1951 m.texmatrix[1] = r_shadow_entitytolight;
1953 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1954 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1957 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1959 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1961 // 1/2/2 3D combine path (original Radeon)
1962 memset(&m, 0, sizeof(m));
1963 m.pointer_vertex = rsurface_vertex3f;
1964 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1966 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1967 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1969 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1970 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1973 GL_ColorMask(0,0,0,1);
1974 GL_BlendFunc(GL_ONE, GL_ZERO);
1975 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1976 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1977 GL_LockArrays(0, 0);
1979 memset(&m, 0, sizeof(m));
1980 m.pointer_vertex = rsurface_vertex3f;
1981 m.tex[0] = R_GetTexture(normalmaptexture);
1982 m.texcombinergb[0] = GL_REPLACE;
1983 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1984 m.texmatrix[0] = texture->currenttexmatrix;
1985 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1986 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1987 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1988 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);
1990 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1991 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1992 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1993 GL_LockArrays(0, 0);
1995 memset(&m, 0, sizeof(m));
1996 m.pointer_vertex = rsurface_vertex3f;
1997 m.tex[0] = R_GetTexture(basetexture);
1998 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1999 m.texmatrix[0] = texture->currenttexmatrix;
2000 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2002 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2004 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2005 m.texmatrix[1] = r_shadow_entitytolight;
2007 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2008 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2011 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2013 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
2015 // 2/2 3D combine path (original Radeon)
2016 memset(&m, 0, sizeof(m));
2017 m.pointer_vertex = rsurface_vertex3f;
2018 m.tex[0] = R_GetTexture(normalmaptexture);
2019 m.texcombinergb[0] = GL_REPLACE;
2020 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2021 m.texmatrix[0] = texture->currenttexmatrix;
2022 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2023 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2024 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2025 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);
2027 GL_ColorMask(0,0,0,1);
2028 GL_BlendFunc(GL_ONE, GL_ZERO);
2029 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2030 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2031 GL_LockArrays(0, 0);
2033 memset(&m, 0, sizeof(m));
2034 m.pointer_vertex = rsurface_vertex3f;
2035 m.tex[0] = R_GetTexture(basetexture);
2036 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2037 m.texmatrix[0] = texture->currenttexmatrix;
2038 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2040 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2041 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2043 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2044 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2046 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2048 else if (r_textureunits.integer >= 4)
2050 // 4/2 2D combine path (Geforce3, Radeon 8500)
2051 memset(&m, 0, sizeof(m));
2052 m.pointer_vertex = rsurface_vertex3f;
2053 m.tex[0] = R_GetTexture(normalmaptexture);
2054 m.texcombinergb[0] = GL_REPLACE;
2055 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2056 m.texmatrix[0] = texture->currenttexmatrix;
2057 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2058 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2059 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2060 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);
2061 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2063 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2064 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2066 m.pointer_texcoord[2] = varray_texcoord2f[2];
2067 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2069 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2071 m.pointer_texcoord3f[3] = rsurface_vertex3f;
2072 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2074 m.pointer_texcoord[3] = varray_texcoord2f[3];
2075 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2078 GL_ColorMask(0,0,0,1);
2079 GL_BlendFunc(GL_ONE, GL_ZERO);
2080 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2081 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2082 GL_LockArrays(0, 0);
2084 memset(&m, 0, sizeof(m));
2085 m.pointer_vertex = rsurface_vertex3f;
2086 m.tex[0] = R_GetTexture(basetexture);
2087 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2088 m.texmatrix[0] = texture->currenttexmatrix;
2089 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2091 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2093 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2094 m.texmatrix[1] = r_shadow_entitytolight;
2096 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2097 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2100 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2104 // 2/2/2 2D combine path (any dot3 card)
2105 memset(&m, 0, sizeof(m));
2106 m.pointer_vertex = rsurface_vertex3f;
2107 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2109 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2110 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2112 m.pointer_texcoord[0] = varray_texcoord2f[0];
2113 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2115 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2117 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2118 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2120 m.pointer_texcoord[1] = varray_texcoord2f[1];
2121 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2124 GL_ColorMask(0,0,0,1);
2125 GL_BlendFunc(GL_ONE, GL_ZERO);
2126 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2127 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2128 GL_LockArrays(0, 0);
2130 memset(&m, 0, sizeof(m));
2131 m.pointer_vertex = rsurface_vertex3f;
2132 m.tex[0] = R_GetTexture(normalmaptexture);
2133 m.texcombinergb[0] = GL_REPLACE;
2134 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2135 m.texmatrix[0] = texture->currenttexmatrix;
2136 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2137 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2138 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2139 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);
2141 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2142 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2143 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2144 GL_LockArrays(0, 0);
2146 memset(&m, 0, sizeof(m));
2147 m.pointer_vertex = rsurface_vertex3f;
2148 m.tex[0] = R_GetTexture(basetexture);
2149 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2150 m.texmatrix[0] = texture->currenttexmatrix;
2151 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2153 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2155 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2156 m.texmatrix[1] = r_shadow_entitytolight;
2158 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2159 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2162 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2164 // this final code is shared
2166 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2167 VectorScale(lightcolorbase, colorscale, color2);
2168 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2169 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2171 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2172 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2174 GL_LockArrays(0, 0);
2177 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
2182 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2183 // FIXME: detect blendsquare!
2184 //if (!gl_support_blendsquare)
2187 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2189 // 2/0/0/1/2 3D combine blendsquare path
2190 memset(&m, 0, sizeof(m));
2191 m.pointer_vertex = rsurface_vertex3f;
2192 m.tex[0] = R_GetTexture(normalmaptexture);
2193 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2194 m.texmatrix[0] = texture->currenttexmatrix;
2195 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2196 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2197 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2198 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);
2200 GL_ColorMask(0,0,0,1);
2201 // this squares the result
2202 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2203 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2204 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2205 GL_LockArrays(0, 0);
2207 memset(&m, 0, sizeof(m));
2208 m.pointer_vertex = rsurface_vertex3f;
2210 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2211 // square alpha in framebuffer a few times to make it shiny
2212 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2213 // these comments are a test run through this math for intensity 0.5
2214 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2215 // 0.25 * 0.25 = 0.0625 (this is another pass)
2216 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2217 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2218 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2219 GL_LockArrays(0, 0);
2221 memset(&m, 0, sizeof(m));
2222 m.pointer_vertex = rsurface_vertex3f;
2223 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2225 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2226 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2228 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2229 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2232 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2233 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2234 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2235 GL_LockArrays(0, 0);
2237 memset(&m, 0, sizeof(m));
2238 m.pointer_vertex = rsurface_vertex3f;
2239 m.tex[0] = R_GetTexture(glosstexture);
2240 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2241 m.texmatrix[0] = texture->currenttexmatrix;
2242 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2244 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2246 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2247 m.texmatrix[1] = r_shadow_entitytolight;
2249 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2250 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2253 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2255 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2257 // 2/0/0/2 3D combine blendsquare path
2258 memset(&m, 0, sizeof(m));
2259 m.pointer_vertex = rsurface_vertex3f;
2260 m.tex[0] = R_GetTexture(normalmaptexture);
2261 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2262 m.texmatrix[0] = texture->currenttexmatrix;
2263 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2264 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2265 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2266 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);
2268 GL_ColorMask(0,0,0,1);
2269 // this squares the result
2270 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2271 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2272 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2273 GL_LockArrays(0, 0);
2275 memset(&m, 0, sizeof(m));
2276 m.pointer_vertex = rsurface_vertex3f;
2278 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2279 // square alpha in framebuffer a few times to make it shiny
2280 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2281 // these comments are a test run through this math for intensity 0.5
2282 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2283 // 0.25 * 0.25 = 0.0625 (this is another pass)
2284 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2285 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2286 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2287 GL_LockArrays(0, 0);
2289 memset(&m, 0, sizeof(m));
2290 m.pointer_vertex = rsurface_vertex3f;
2291 m.tex[0] = R_GetTexture(glosstexture);
2292 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2293 m.texmatrix[0] = texture->currenttexmatrix;
2294 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2296 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2297 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2299 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2300 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2302 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2306 // 2/0/0/2/2 2D combine blendsquare path
2307 memset(&m, 0, sizeof(m));
2308 m.pointer_vertex = rsurface_vertex3f;
2309 m.tex[0] = R_GetTexture(normalmaptexture);
2310 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2311 m.texmatrix[0] = texture->currenttexmatrix;
2312 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2313 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2314 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2315 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);
2317 GL_ColorMask(0,0,0,1);
2318 // this squares the result
2319 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2320 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2321 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2322 GL_LockArrays(0, 0);
2324 memset(&m, 0, sizeof(m));
2325 m.pointer_vertex = rsurface_vertex3f;
2327 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2328 // square alpha in framebuffer a few times to make it shiny
2329 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2330 // these comments are a test run through this math for intensity 0.5
2331 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2332 // 0.25 * 0.25 = 0.0625 (this is another pass)
2333 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2334 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2335 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2336 GL_LockArrays(0, 0);
2338 memset(&m, 0, sizeof(m));
2339 m.pointer_vertex = rsurface_vertex3f;
2340 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2342 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2343 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2345 m.pointer_texcoord[0] = varray_texcoord2f[0];
2346 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2348 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2350 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2351 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2353 m.pointer_texcoord[1] = varray_texcoord2f[1];
2354 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2357 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2358 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2359 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2360 GL_LockArrays(0, 0);
2362 memset(&m, 0, sizeof(m));
2363 m.pointer_vertex = rsurface_vertex3f;
2364 m.tex[0] = R_GetTexture(glosstexture);
2365 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2366 m.texmatrix[0] = texture->currenttexmatrix;
2367 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2369 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2371 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2372 m.texmatrix[1] = r_shadow_entitytolight;
2374 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2375 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2378 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2381 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2382 VectorScale(lightcolorbase, colorscale, color2);
2383 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2384 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2386 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2387 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2389 GL_LockArrays(0, 0);
2392 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, qboolean dopants, qboolean doshirt)
2394 // ARB path (any Geforce, any Radeon)
2395 int surfacelistindex;
2396 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
2397 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
2398 qboolean dospecular = specularscale > 0;
2399 if (!doambient && !dodiffuse && !dospecular)
2401 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2403 const msurface_t *surface = surfacelist[surfacelistindex];
2404 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
2405 if (!rsurface_svector3f)
2407 rsurface_svector3f = varray_svector3f;
2408 rsurface_tvector3f = varray_tvector3f;
2409 rsurface_normal3f = varray_normal3f;
2410 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);
2413 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
2415 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2419 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
2421 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2426 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
2428 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2431 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(ent, texture, surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
2435 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
2438 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2439 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
2440 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
2445 // due to low fillrate on the cards this vertex lighting path is
2446 // designed for, we manually cull all triangles that do not
2447 // contain a lit vertex
2450 int newnumtriangles;
2452 int newelements[3072];
2454 newnumtriangles = 0;
2456 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
2458 if (newnumtriangles >= 1024)
2460 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2461 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
2462 GL_LockArrays(0, 0);
2463 newnumtriangles = 0;
2466 if (VectorLength2(varray_color4f + e[0] * 4) + VectorLength2(varray_color4f + e[1] * 4) + VectorLength2(varray_color4f + e[2] * 4) >= 0.01)
2476 if (newnumtriangles >= 1)
2478 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2479 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
2480 GL_LockArrays(0, 0);
2486 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
2487 if (VectorLength2(c))
2491 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2492 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2493 GL_LockArrays(0, 0);
2495 // now reduce the intensity for the next overbright pass
2496 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
2498 c[0] = max(0, c[0] - 1);
2499 c[1] = max(0, c[1] - 1);
2500 c[2] = max(0, c[2] - 1);
2505 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, qboolean dopants, qboolean doshirt)
2507 int surfacelistindex;
2508 float ambientcolorbase[3], diffusecolorbase[3];
2509 float ambientcolorpants[3], diffusecolorpants[3];
2510 float ambientcolorshirt[3], diffusecolorshirt[3];
2512 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
2513 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
2514 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
2515 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
2516 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
2517 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
2518 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2519 memset(&m, 0, sizeof(m));
2520 m.tex[0] = R_GetTexture(basetexture);
2521 if (r_textureunits.integer >= 2)
2524 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2526 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2528 m.pointer_texcoord[1] = varray_texcoord2f[1];
2529 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2531 if (r_textureunits.integer >= 3)
2533 // Geforce3/Radeon class but not using dot3
2534 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2536 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2538 m.pointer_texcoord[2] = varray_texcoord2f[2];
2539 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2543 m.pointer_color = varray_color4f;
2545 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2547 const msurface_t *surface = surfacelist[surfacelistindex];
2548 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
2549 if (!rsurface_svector3f)
2551 rsurface_svector3f = varray_svector3f;
2552 rsurface_tvector3f = varray_tvector3f;
2553 rsurface_normal3f = varray_normal3f;
2554 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);
2556 // OpenGL 1.1 path (anything)
2557 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2558 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
2559 if (r_textureunits.integer >= 2)
2563 R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
2565 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2567 if (r_textureunits.integer >= 3)
2569 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2571 R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
2573 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2577 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2578 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorbase, ambientcolorbase);
2581 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2582 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorpants, ambientcolorpants);
2586 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2587 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorshirt, ambientcolorshirt);
2592 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
2594 // FIXME: support MATERIALFLAG_NODEPTHTEST
2595 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2596 rtexture_t *basetexture;
2597 rtexture_t *pantstexture;
2598 rtexture_t *shirttexture;
2599 rtexture_t *glosstexture;
2600 float specularscale;
2601 qboolean dopants, doshirt;
2602 glosstexture = r_texture_black;
2604 if (r_shadow_gloss.integer > 0)
2606 if (texture->skin.gloss)
2608 if (r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
2610 glosstexture = texture->skin.gloss;
2611 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
2616 if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
2618 glosstexture = r_texture_white;
2619 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
2623 // calculate colors to render this texture with
2624 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
2625 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
2626 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
2627 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2629 if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
2630 qglDisable(GL_CULL_FACE);
2632 qglEnable(GL_CULL_FACE);
2633 dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
2634 doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2635 if (dopants + doshirt)
2639 lightcolorpants[0] = lightcolorbase[0] * ent->colormap_pantscolor[0];
2640 lightcolorpants[1] = lightcolorbase[1] * ent->colormap_pantscolor[1];
2641 lightcolorpants[2] = lightcolorbase[2] * ent->colormap_pantscolor[2];
2645 pantstexture = r_texture_black;
2646 VectorClear(lightcolorpants);
2650 shirttexture = texture->skin.shirt;
2651 lightcolorshirt[0] = lightcolorbase[0] * ent->colormap_shirtcolor[0];
2652 lightcolorshirt[1] = lightcolorbase[1] * ent->colormap_shirtcolor[1];
2653 lightcolorshirt[2] = lightcolorbase[2] * ent->colormap_shirtcolor[2];
2657 shirttexture = r_texture_black;
2658 VectorClear(lightcolorshirt);
2660 switch (r_shadow_rendermode)
2662 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2663 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, dopants, doshirt);
2665 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2666 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, dopants, doshirt);
2668 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2669 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, dopants, doshirt);
2671 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2672 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, dopants, doshirt);
2675 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2681 basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
2682 switch (r_shadow_rendermode)
2684 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2685 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, false, false);
2687 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2688 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, false, false);
2690 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2691 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, false, false);
2693 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2694 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, false, false);
2697 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2703 void R_RTLight_Update(dlight_t *light, int isstatic)
2707 rtlight_t *rtlight = &light->rtlight;
2708 R_RTLight_Uncompile(rtlight);
2709 memset(rtlight, 0, sizeof(*rtlight));
2711 VectorCopy(light->origin, rtlight->shadoworigin);
2712 VectorCopy(light->color, rtlight->color);
2713 rtlight->radius = light->radius;
2714 //rtlight->cullradius = rtlight->radius;
2715 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2716 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2717 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2718 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2719 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2720 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2721 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2722 rtlight->cubemapname[0] = 0;
2723 if (light->cubemapname[0])
2724 strcpy(rtlight->cubemapname, light->cubemapname);
2725 else if (light->cubemapnum > 0)
2726 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2727 rtlight->shadow = light->shadow;
2728 rtlight->corona = light->corona;
2729 rtlight->style = light->style;
2730 rtlight->isstatic = isstatic;
2731 rtlight->coronasizescale = light->coronasizescale;
2732 rtlight->ambientscale = light->ambientscale;
2733 rtlight->diffusescale = light->diffusescale;
2734 rtlight->specularscale = light->specularscale;
2735 rtlight->flags = light->flags;
2736 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2737 // ConcatScale won't work here because this needs to scale rotate and
2738 // translate, not just rotate
2739 scale = 1.0f / rtlight->radius;
2740 for (k = 0;k < 3;k++)
2741 for (j = 0;j < 4;j++)
2742 rtlight->matrix_worldtolight.m[k][j] *= scale;
2744 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2745 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2746 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2747 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2750 // compiles rtlight geometry
2751 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2752 void R_RTLight_Compile(rtlight_t *rtlight)
2754 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2755 entity_render_t *ent = r_refdef.worldentity;
2756 model_t *model = r_refdef.worldmodel;
2757 unsigned char *data;
2759 // compile the light
2760 rtlight->compiled = true;
2761 rtlight->static_numleafs = 0;
2762 rtlight->static_numleafpvsbytes = 0;
2763 rtlight->static_leaflist = NULL;
2764 rtlight->static_leafpvs = NULL;
2765 rtlight->static_numsurfaces = 0;
2766 rtlight->static_surfacelist = NULL;
2767 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2768 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2769 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2770 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2771 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2772 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2774 if (model && model->GetLightInfo)
2776 // this variable must be set for the CompileShadowVolume code
2777 r_shadow_compilingrtlight = rtlight;
2778 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2779 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);
2780 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2781 data = (unsigned char *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2782 rtlight->static_numleafs = numleafs;
2783 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2784 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2785 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2786 rtlight->static_numsurfaces = numsurfaces;
2787 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2789 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2790 if (numleafpvsbytes)
2791 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2793 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2794 if (model->CompileShadowVolume && rtlight->shadow)
2795 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2796 // now we're done compiling the rtlight
2797 r_shadow_compilingrtlight = NULL;
2801 // use smallest available cullradius - box radius or light radius
2802 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2803 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2807 if (rtlight->static_meshchain_shadow)
2810 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2813 shadowtris += mesh->numtriangles;
2817 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);
2820 void R_RTLight_Uncompile(rtlight_t *rtlight)
2822 if (rtlight->compiled)
2824 if (rtlight->static_meshchain_shadow)
2825 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2826 rtlight->static_meshchain_shadow = NULL;
2827 // these allocations are grouped
2828 if (rtlight->static_leaflist)
2829 Mem_Free(rtlight->static_leaflist);
2830 rtlight->static_numleafs = 0;
2831 rtlight->static_numleafpvsbytes = 0;
2832 rtlight->static_leaflist = NULL;
2833 rtlight->static_leafpvs = NULL;
2834 rtlight->static_numsurfaces = 0;
2835 rtlight->static_surfacelist = NULL;
2836 rtlight->compiled = false;
2840 void R_Shadow_UncompileWorldLights(void)
2843 for (light = r_shadow_worldlightchain;light;light = light->next)
2844 R_RTLight_Uncompile(&light->rtlight);
2847 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2849 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2850 vec_t relativeshadowradius;
2851 if (ent == r_refdef.worldentity)
2853 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2856 R_Mesh_Matrix(&ent->matrix);
2857 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2859 renderstats.lights_shadowtriangles += mesh->numtriangles;
2860 R_Mesh_VertexPointer(mesh->vertex3f);
2861 GL_LockArrays(0, mesh->numverts);
2862 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2864 // decrement stencil if backface is behind depthbuffer
2865 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2866 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2867 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2868 // increment stencil if frontface is behind depthbuffer
2869 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2870 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2872 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2873 GL_LockArrays(0, 0);
2876 else if (numsurfaces)
2878 R_Mesh_Matrix(&ent->matrix);
2879 ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2884 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2885 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2886 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2887 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2888 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2889 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2890 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2891 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2892 R_Mesh_Matrix(&ent->matrix);
2893 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2897 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2899 // set up properties for rendering light onto this entity
2900 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2901 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2902 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2903 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2904 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2905 R_Mesh_Matrix(&ent->matrix);
2908 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2910 R_Shadow_SetupEntityLight(ent);
2911 if (ent == r_refdef.worldentity)
2912 ent->model->DrawLight(ent, numsurfaces, surfacelist);
2914 ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
2917 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2921 int numleafs, numsurfaces;
2922 int *leaflist, *surfacelist;
2923 unsigned char *leafpvs;
2924 int numlightentities;
2925 int numshadowentities;
2926 entity_render_t *lightentities[MAX_EDICTS];
2927 entity_render_t *shadowentities[MAX_EDICTS];
2929 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2930 // skip lights that are basically invisible (color 0 0 0)
2931 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2934 // loading is done before visibility checks because loading should happen
2935 // all at once at the start of a level, not when it stalls gameplay.
2936 // (especially important to benchmarks)
2938 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2939 R_RTLight_Compile(rtlight);
2941 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2943 // look up the light style value at this time
2944 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2945 VectorScale(rtlight->color, f, rtlight->currentcolor);
2947 if (rtlight->selected)
2949 f = 2 + sin(realtime * M_PI * 4.0);
2950 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2954 // if lightstyle is currently off, don't draw the light
2955 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2958 // if the light box is offscreen, skip it
2959 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2962 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2964 // compiled light, world available and can receive realtime lighting
2965 // retrieve leaf information
2966 numleafs = rtlight->static_numleafs;
2967 leaflist = rtlight->static_leaflist;
2968 leafpvs = rtlight->static_leafpvs;
2969 numsurfaces = rtlight->static_numsurfaces;
2970 surfacelist = rtlight->static_surfacelist;
2972 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2974 // dynamic light, world available and can receive realtime lighting
2975 // calculate lit surfaces and leafs
2976 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2977 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);
2978 leaflist = r_shadow_buffer_leaflist;
2979 leafpvs = r_shadow_buffer_leafpvs;
2980 surfacelist = r_shadow_buffer_surfacelist;
2981 // if the reduced leaf bounds are offscreen, skip it
2982 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2994 // check if light is illuminating any visible leafs
2997 for (i = 0;i < numleafs;i++)
2998 if (r_worldleafvisible[leaflist[i]])
3003 // set up a scissor rectangle for this light
3004 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
3007 // make a list of lit entities and shadow casting entities
3008 numlightentities = 0;
3009 numshadowentities = 0;
3010 // don't count the world unless some surfaces are actually lit
3013 lightentities[numlightentities++] = r_refdef.worldentity;
3014 shadowentities[numshadowentities++] = r_refdef.worldentity;
3016 // add dynamic entities that are lit by the light
3017 if (r_drawentities.integer)
3019 for (i = 0;i < r_refdef.numentities;i++)
3021 entity_render_t *ent = r_refdef.entities[i];
3022 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
3024 && !(ent->flags & RENDER_TRANSPARENT)
3025 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
3027 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3028 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
3029 shadowentities[numshadowentities++] = ent;
3030 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
3031 lightentities[numlightentities++] = ent;
3036 // return if there's nothing at all to light
3037 if (!numlightentities)
3040 // don't let sound skip if going slow
3041 if (r_refdef.extraupdate)
3044 // make this the active rtlight for rendering purposes
3045 R_Shadow_RenderMode_ActiveLight(rtlight);
3046 // count this light in the r_speeds
3047 renderstats.lights++;
3050 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
3052 // draw stencil shadow volumes to mask off pixels that are in shadow
3053 // so that they won't receive lighting
3057 R_Shadow_RenderMode_StencilShadowVolumes();
3058 for (i = 0;i < numshadowentities;i++)
3059 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
3062 // optionally draw visible shape of the shadow volumes
3063 // for performance analysis by level designers
3064 if (r_showshadowvolumes.integer)
3066 R_Shadow_RenderMode_VisibleShadowVolumes();
3067 for (i = 0;i < numshadowentities;i++)
3068 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
3072 if (numlightentities)
3074 // draw lighting in the unmasked areas
3075 R_Shadow_RenderMode_Lighting(usestencil, false);
3076 for (i = 0;i < numlightentities;i++)
3077 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3079 // optionally draw the illuminated areas
3080 // for performance analysis by level designers
3081 if (r_showlighting.integer)
3083 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
3084 for (i = 0;i < numlightentities;i++)
3085 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3090 void R_ShadowVolumeLighting(qboolean visible)
3095 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3096 R_Shadow_EditLights_Reload_f();
3098 R_Shadow_RenderMode_Begin();
3100 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3101 if (r_shadow_debuglight.integer >= 0)
3103 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3104 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3105 R_DrawRTLight(&light->rtlight, visible);
3108 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3109 if (light->flags & flag)
3110 R_DrawRTLight(&light->rtlight, visible);
3112 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3113 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
3115 R_Shadow_RenderMode_End();
3118 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3119 typedef struct suffixinfo_s
3122 qboolean flipx, flipy, flipdiagonal;
3125 static suffixinfo_t suffix[3][6] =
3128 {"px", false, false, false},
3129 {"nx", false, false, false},
3130 {"py", false, false, false},
3131 {"ny", false, false, false},
3132 {"pz", false, false, false},
3133 {"nz", false, false, false}
3136 {"posx", false, false, false},
3137 {"negx", false, false, false},
3138 {"posy", false, false, false},
3139 {"negy", false, false, false},
3140 {"posz", false, false, false},
3141 {"negz", false, false, false}
3144 {"rt", true, false, true},
3145 {"lf", false, true, true},
3146 {"ft", true, true, false},
3147 {"bk", false, false, false},
3148 {"up", true, false, true},
3149 {"dn", true, false, true}
3153 static int componentorder[4] = {0, 1, 2, 3};
3155 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3157 int i, j, cubemapsize;
3158 unsigned char *cubemappixels, *image_rgba;
3159 rtexture_t *cubemaptexture;
3161 // must start 0 so the first loadimagepixels has no requested width/height
3163 cubemappixels = NULL;
3164 cubemaptexture = NULL;
3165 // keep trying different suffix groups (posx, px, rt) until one loads
3166 for (j = 0;j < 3 && !cubemappixels;j++)
3168 // load the 6 images in the suffix group
3169 for (i = 0;i < 6;i++)
3171 // generate an image name based on the base and and suffix
3172 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3174 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3176 // an image loaded, make sure width and height are equal
3177 if (image_width == image_height)
3179 // if this is the first image to load successfully, allocate the cubemap memory
3180 if (!cubemappixels && image_width >= 1)
3182 cubemapsize = image_width;
3183 // note this clears to black, so unavailable sides are black
3184 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3186 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3188 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);
3191 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3193 Mem_Free(image_rgba);
3197 // if a cubemap loaded, upload it
3200 if (!r_shadow_filters_texturepool)
3201 r_shadow_filters_texturepool = R_AllocTexturePool();
3202 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3203 Mem_Free(cubemappixels);
3207 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3208 for (j = 0;j < 3;j++)
3209 for (i = 0;i < 6;i++)
3210 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3211 Con_Print(" and was unable to find any of them.\n");
3213 return cubemaptexture;
3216 rtexture_t *R_Shadow_Cubemap(const char *basename)
3219 for (i = 0;i < numcubemaps;i++)
3220 if (!strcasecmp(cubemaps[i].basename, basename))
3221 return cubemaps[i].texture;
3222 if (i >= MAX_CUBEMAPS)
3223 return r_texture_whitecube;
3225 strcpy(cubemaps[i].basename, basename);
3226 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3227 if (!cubemaps[i].texture)
3228 cubemaps[i].texture = r_texture_whitecube;
3229 return cubemaps[i].texture;
3232 void R_Shadow_FreeCubemaps(void)
3235 R_FreeTexturePool(&r_shadow_filters_texturepool);
3238 dlight_t *R_Shadow_NewWorldLight(void)
3241 light = (dlight_t *)Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3242 light->next = r_shadow_worldlightchain;
3243 r_shadow_worldlightchain = light;
3247 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)
3249 VectorCopy(origin, light->origin);
3250 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3251 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3252 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3253 light->color[0] = max(color[0], 0);
3254 light->color[1] = max(color[1], 0);
3255 light->color[2] = max(color[2], 0);
3256 light->radius = max(radius, 0);
3257 light->style = style;
3258 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3260 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3263 light->shadow = shadowenable;
3264 light->corona = corona;
3267 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3268 light->coronasizescale = coronasizescale;
3269 light->ambientscale = ambientscale;
3270 light->diffusescale = diffusescale;
3271 light->specularscale = specularscale;
3272 light->flags = flags;
3273 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3275 R_RTLight_Update(light, true);
3278 void R_Shadow_FreeWorldLight(dlight_t *light)
3280 dlight_t **lightpointer;
3281 R_RTLight_Uncompile(&light->rtlight);
3282 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3283 if (*lightpointer != light)
3284 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3285 *lightpointer = light->next;
3289 void R_Shadow_ClearWorldLights(void)
3291 while (r_shadow_worldlightchain)
3292 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3293 r_shadow_selectedlight = NULL;
3294 R_Shadow_FreeCubemaps();
3297 void R_Shadow_SelectLight(dlight_t *light)
3299 if (r_shadow_selectedlight)
3300 r_shadow_selectedlight->selected = false;
3301 r_shadow_selectedlight = light;
3302 if (r_shadow_selectedlight)
3303 r_shadow_selectedlight->selected = true;
3306 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
3308 float scale = r_editlights_cursorgrid.value * 0.5f;
3309 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[0]->tex, NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
3312 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
3315 const dlight_t *light = (dlight_t *)ent;
3317 if (light->selected)
3318 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3321 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacenumber]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
3324 void R_Shadow_DrawLightSprites(void)
3329 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3330 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, i % NUMCROSSHAIRS, &light->rtlight);
3331 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3334 void R_Shadow_SelectLightInView(void)
3336 float bestrating, rating, temp[3];
3337 dlight_t *best, *light;
3340 for (light = r_shadow_worldlightchain;light;light = light->next)
3342 VectorSubtract(light->origin, r_vieworigin, temp);
3343 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3346 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3347 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3349 bestrating = rating;
3354 R_Shadow_SelectLight(best);
3357 void R_Shadow_LoadWorldLights(void)
3359 int n, a, style, shadow, flags;
3360 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3361 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3362 if (r_refdef.worldmodel == NULL)
3364 Con_Print("No map loaded.\n");
3367 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3368 strlcat (name, ".rtlights", sizeof (name));
3369 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3379 for (;COM_Parse(t, true) && strcmp(
3380 if (COM_Parse(t, true))
3382 if (com_token[0] == '!')
3385 origin[0] = atof(com_token+1);
3388 origin[0] = atof(com_token);
3393 while (*s && *s != '\n' && *s != '\r')
3399 // check for modifier flags
3406 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);
3409 flags = LIGHTFLAG_REALTIMEMODE;
3417 coronasizescale = 0.25f;
3419 VectorClear(angles);
3422 if (a < 9 || !strcmp(cubemapname, "\"\""))
3424 // remove quotes on cubemapname
3425 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3427 cubemapname[strlen(cubemapname)-1] = 0;
3428 strcpy(cubemapname, cubemapname + 1);
3432 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);
3435 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3443 Con_Printf("invalid rtlights file \"%s\"\n", name);
3444 Mem_Free(lightsstring);
3448 void R_Shadow_SaveWorldLights(void)
3451 size_t bufchars, bufmaxchars;
3453 char name[MAX_QPATH];
3454 char line[MAX_INPUTLINE];
3455 if (!r_shadow_worldlightchain)
3457 if (r_refdef.worldmodel == NULL)
3459 Con_Print("No map loaded.\n");
3462 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3463 strlcat (name, ".rtlights", sizeof (name));
3464 bufchars = bufmaxchars = 0;
3466 for (light = r_shadow_worldlightchain;light;light = light->next)
3468 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3469 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);
3470 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3471 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]);
3473 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);
3474 if (bufchars + strlen(line) > bufmaxchars)
3476 bufmaxchars = bufchars + strlen(line) + 2048;
3478 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3482 memcpy(buf, oldbuf, bufchars);
3488 memcpy(buf + bufchars, line, strlen(line));
3489 bufchars += strlen(line);
3493 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3498 void R_Shadow_LoadLightsFile(void)
3501 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3502 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3503 if (r_refdef.worldmodel == NULL)
3505 Con_Print("No map loaded.\n");
3508 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3509 strlcat (name, ".lights", sizeof (name));
3510 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3518 while (*s && *s != '\n' && *s != '\r')
3524 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);
3528 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);
3531 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3532 radius = bound(15, radius, 4096);
3533 VectorScale(color, (2.0f / (8388608.0f)), color);
3534 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3542 Con_Printf("invalid lights file \"%s\"\n", name);
3543 Mem_Free(lightsstring);
3547 // tyrlite/hmap2 light types in the delay field
3548 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3550 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3552 int entnum, style, islight, skin, pflags, effects, type, n;
3555 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3556 char key[256], value[MAX_INPUTLINE];
3558 if (r_refdef.worldmodel == NULL)
3560 Con_Print("No map loaded.\n");
3563 // try to load a .ent file first
3564 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3565 strlcat (key, ".ent", sizeof (key));
3566 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3567 // and if that is not found, fall back to the bsp file entity string
3569 data = r_refdef.worldmodel->brush.entities;
3572 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3574 type = LIGHTTYPE_MINUSX;
3575 origin[0] = origin[1] = origin[2] = 0;
3576 originhack[0] = originhack[1] = originhack[2] = 0;
3577 angles[0] = angles[1] = angles[2] = 0;
3578 color[0] = color[1] = color[2] = 1;
3579 light[0] = light[1] = light[2] = 1;light[3] = 300;
3580 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3590 if (!COM_ParseToken(&data, false))
3592 if (com_token[0] == '}')
3593 break; // end of entity
3594 if (com_token[0] == '_')
3595 strcpy(key, com_token + 1);
3597 strcpy(key, com_token);
3598 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3599 key[strlen(key)-1] = 0;
3600 if (!COM_ParseToken(&data, false))
3602 strcpy(value, com_token);
3604 // now that we have the key pair worked out...
3605 if (!strcmp("light", key))
3607 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3611 light[0] = vec[0] * (1.0f / 256.0f);
3612 light[1] = vec[0] * (1.0f / 256.0f);
3613 light[2] = vec[0] * (1.0f / 256.0f);
3619 light[0] = vec[0] * (1.0f / 255.0f);
3620 light[1] = vec[1] * (1.0f / 255.0f);
3621 light[2] = vec[2] * (1.0f / 255.0f);
3625 else if (!strcmp("delay", key))
3627 else if (!strcmp("origin", key))
3628 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3629 else if (!strcmp("angle", key))
3630 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3631 else if (!strcmp("angles", key))
3632 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3633 else if (!strcmp("color", key))
3634 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3635 else if (!strcmp("wait", key))
3636 fadescale = atof(value);
3637 else if (!strcmp("classname", key))
3639 if (!strncmp(value, "light", 5))
3642 if (!strcmp(value, "light_fluoro"))
3647 overridecolor[0] = 1;
3648 overridecolor[1] = 1;
3649 overridecolor[2] = 1;
3651 if (!strcmp(value, "light_fluorospark"))
3656 overridecolor[0] = 1;
3657 overridecolor[1] = 1;
3658 overridecolor[2] = 1;
3660 if (!strcmp(value, "light_globe"))
3665 overridecolor[0] = 1;
3666 overridecolor[1] = 0.8;
3667 overridecolor[2] = 0.4;
3669 if (!strcmp(value, "light_flame_large_yellow"))
3674 overridecolor[0] = 1;
3675 overridecolor[1] = 0.5;
3676 overridecolor[2] = 0.1;
3678 if (!strcmp(value, "light_flame_small_yellow"))
3683 overridecolor[0] = 1;
3684 overridecolor[1] = 0.5;
3685 overridecolor[2] = 0.1;
3687 if (!strcmp(value, "light_torch_small_white"))
3692 overridecolor[0] = 1;
3693 overridecolor[1] = 0.5;
3694 overridecolor[2] = 0.1;
3696 if (!strcmp(value, "light_torch_small_walltorch"))
3701 overridecolor[0] = 1;
3702 overridecolor[1] = 0.5;
3703 overridecolor[2] = 0.1;
3707 else if (!strcmp("style", key))
3708 style = atoi(value);
3709 else if (!strcmp("skin", key))
3710 skin = (int)atof(value);
3711 else if (!strcmp("pflags", key))
3712 pflags = (int)atof(value);
3713 else if (!strcmp("effects", key))
3714 effects = (int)atof(value);
3715 else if (r_refdef.worldmodel->type == mod_brushq3)
3717 if (!strcmp("scale", key))
3718 lightscale = atof(value);
3719 if (!strcmp("fade", key))
3720 fadescale = atof(value);
3725 if (lightscale <= 0)
3729 if (color[0] == color[1] && color[0] == color[2])
3731 color[0] *= overridecolor[0];
3732 color[1] *= overridecolor[1];
3733 color[2] *= overridecolor[2];
3735 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3736 color[0] = color[0] * light[0];
3737 color[1] = color[1] * light[1];
3738 color[2] = color[2] * light[2];
3741 case LIGHTTYPE_MINUSX:
3743 case LIGHTTYPE_RECIPX:
3745 VectorScale(color, (1.0f / 16.0f), color);
3747 case LIGHTTYPE_RECIPXX:
3749 VectorScale(color, (1.0f / 16.0f), color);
3752 case LIGHTTYPE_NONE:
3756 case LIGHTTYPE_MINUSXX:
3759 VectorAdd(origin, originhack, origin);
3761 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);
3764 Mem_Free(entfiledata);
3768 void R_Shadow_SetCursorLocationForView(void)
3771 vec3_t dest, endpos;
3773 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3774 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3775 if (trace.fraction < 1)
3777 dist = trace.fraction * r_editlights_cursordistance.value;
3778 push = r_editlights_cursorpushback.value;
3782 VectorMA(trace.endpos, push, r_viewforward, endpos);
3783 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3787 VectorClear( endpos );
3789 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3790 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3791 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3794 void R_Shadow_UpdateWorldLightSelection(void)
3796 if (r_editlights.integer)
3798 R_Shadow_SetCursorLocationForView();
3799 R_Shadow_SelectLightInView();
3800 R_Shadow_DrawLightSprites();
3803 R_Shadow_SelectLight(NULL);
3806 void R_Shadow_EditLights_Clear_f(void)
3808 R_Shadow_ClearWorldLights();
3811 void R_Shadow_EditLights_Reload_f(void)
3813 if (!r_refdef.worldmodel)
3815 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3816 R_Shadow_ClearWorldLights();
3817 R_Shadow_LoadWorldLights();
3818 if (r_shadow_worldlightchain == NULL)
3820 R_Shadow_LoadLightsFile();
3821 if (r_shadow_worldlightchain == NULL)
3822 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3826 void R_Shadow_EditLights_Save_f(void)
3828 if (!r_refdef.worldmodel)
3830 R_Shadow_SaveWorldLights();
3833 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3835 R_Shadow_ClearWorldLights();
3836 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3839 void R_Shadow_EditLights_ImportLightsFile_f(void)
3841 R_Shadow_ClearWorldLights();
3842 R_Shadow_LoadLightsFile();
3845 void R_Shadow_EditLights_Spawn_f(void)
3848 if (!r_editlights.integer)
3850 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3853 if (Cmd_Argc() != 1)
3855 Con_Print("r_editlights_spawn does not take parameters\n");
3858 color[0] = color[1] = color[2] = 1;
3859 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3862 void R_Shadow_EditLights_Edit_f(void)
3864 vec3_t origin, angles, color;
3865 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3866 int style, shadows, flags, normalmode, realtimemode;
3867 char cubemapname[MAX_INPUTLINE];
3868 if (!r_editlights.integer)
3870 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3873 if (!r_shadow_selectedlight)
3875 Con_Print("No selected light.\n");
3878 VectorCopy(r_shadow_selectedlight->origin, origin);
3879 VectorCopy(r_shadow_selectedlight->angles, angles);
3880 VectorCopy(r_shadow_selectedlight->color, color);
3881 radius = r_shadow_selectedlight->radius;
3882 style = r_shadow_selectedlight->style;
3883 if (r_shadow_selectedlight->cubemapname)
3884 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3887 shadows = r_shadow_selectedlight->shadow;
3888 corona = r_shadow_selectedlight->corona;
3889 coronasizescale = r_shadow_selectedlight->coronasizescale;
3890 ambientscale = r_shadow_selectedlight->ambientscale;
3891 diffusescale = r_shadow_selectedlight->diffusescale;
3892 specularscale = r_shadow_selectedlight->specularscale;
3893 flags = r_shadow_selectedlight->flags;
3894 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3895 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3896 if (!strcmp(Cmd_Argv(1), "origin"))
3898 if (Cmd_Argc() != 5)
3900 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3903 origin[0] = atof(Cmd_Argv(2));
3904 origin[1] = atof(Cmd_Argv(3));
3905 origin[2] = atof(Cmd_Argv(4));
3907 else if (!strcmp(Cmd_Argv(1), "originx"))
3909 if (Cmd_Argc() != 3)
3911 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3914 origin[0] = atof(Cmd_Argv(2));
3916 else if (!strcmp(Cmd_Argv(1), "originy"))
3918 if (Cmd_Argc() != 3)
3920 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3923 origin[1] = atof(Cmd_Argv(2));
3925 else if (!strcmp(Cmd_Argv(1), "originz"))
3927 if (Cmd_Argc() != 3)
3929 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3932 origin[2] = atof(Cmd_Argv(2));
3934 else if (!strcmp(Cmd_Argv(1), "move"))
3936 if (Cmd_Argc() != 5)
3938 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3941 origin[0] += atof(Cmd_Argv(2));
3942 origin[1] += atof(Cmd_Argv(3));
3943 origin[2] += atof(Cmd_Argv(4));
3945 else if (!strcmp(Cmd_Argv(1), "movex"))
3947 if (Cmd_Argc() != 3)
3949 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3952 origin[0] += atof(Cmd_Argv(2));
3954 else if (!strcmp(Cmd_Argv(1), "movey"))
3956 if (Cmd_Argc() != 3)
3958 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3961 origin[1] += atof(Cmd_Argv(2));
3963 else if (!strcmp(Cmd_Argv(1), "movez"))
3965 if (Cmd_Argc() != 3)
3967 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3970 origin[2] += atof(Cmd_Argv(2));
3972 else if (!strcmp(Cmd_Argv(1), "angles"))
3974 if (Cmd_Argc() != 5)
3976 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3979 angles[0] = atof(Cmd_Argv(2));
3980 angles[1] = atof(Cmd_Argv(3));
3981 angles[2] = atof(Cmd_Argv(4));
3983 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3985 if (Cmd_Argc() != 3)
3987 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3990 angles[0] = atof(Cmd_Argv(2));
3992 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3994 if (Cmd_Argc() != 3)
3996 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3999 angles[1] = atof(Cmd_Argv(2));
4001 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4003 if (Cmd_Argc() != 3)
4005 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4008 angles[2] = atof(Cmd_Argv(2));
4010 else if (!strcmp(Cmd_Argv(1), "color"))
4012 if (Cmd_Argc() != 5)
4014 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4017 color[0] = atof(Cmd_Argv(2));
4018 color[1] = atof(Cmd_Argv(3));
4019 color[2] = atof(Cmd_Argv(4));
4021 else if (!strcmp(Cmd_Argv(1), "radius"))
4023 if (Cmd_Argc() != 3)
4025 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4028 radius = atof(Cmd_Argv(2));
4030 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4032 if (Cmd_Argc() == 3)
4034 double scale = atof(Cmd_Argv(2));
4041 if (Cmd_Argc() != 5)
4043 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4046 color[0] *= atof(Cmd_Argv(2));
4047 color[1] *= atof(Cmd_Argv(3));
4048 color[2] *= atof(Cmd_Argv(4));
4051 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4053 if (Cmd_Argc() != 3)
4055 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4058 radius *= atof(Cmd_Argv(2));
4060 else if (!strcmp(Cmd_Argv(1), "style"))
4062 if (Cmd_Argc() != 3)
4064 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4067 style = atoi(Cmd_Argv(2));
4069 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4073 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4076 if (Cmd_Argc() == 3)
4077 strcpy(cubemapname, Cmd_Argv(2));
4081 else if (!strcmp(Cmd_Argv(1), "shadows"))
4083 if (Cmd_Argc() != 3)
4085 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4088 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4090 else if (!strcmp(Cmd_Argv(1), "corona"))
4092 if (Cmd_Argc() != 3)
4094 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4097 corona = atof(Cmd_Argv(2));
4099 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4101 if (Cmd_Argc() != 3)
4103 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4106 coronasizescale = atof(Cmd_Argv(2));
4108 else if (!strcmp(Cmd_Argv(1), "ambient"))
4110 if (Cmd_Argc() != 3)
4112 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4115 ambientscale = atof(Cmd_Argv(2));
4117 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4119 if (Cmd_Argc() != 3)
4121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4124 diffusescale = atof(Cmd_Argv(2));
4126 else if (!strcmp(Cmd_Argv(1), "specular"))
4128 if (Cmd_Argc() != 3)
4130 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4133 specularscale = atof(Cmd_Argv(2));
4135 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4137 if (Cmd_Argc() != 3)
4139 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4142 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4144 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4146 if (Cmd_Argc() != 3)
4148 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4151 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4155 Con_Print("usage: r_editlights_edit [property] [value]\n");
4156 Con_Print("Selected light's properties:\n");
4157 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4158 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4159 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4160 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4161 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4162 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4163 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4164 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4165 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4166 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4167 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4168 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4169 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4170 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4173 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4174 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4177 void R_Shadow_EditLights_EditAll_f(void)
4181 if (!r_editlights.integer)
4183 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4187 for (light = r_shadow_worldlightchain;light;light = light->next)
4189 R_Shadow_SelectLight(light);
4190 R_Shadow_EditLights_Edit_f();
4194 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4196 int lightnumber, lightcount;
4200 if (!r_editlights.integer)
4206 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4207 if (light == r_shadow_selectedlight)
4208 lightnumber = lightcount;
4209 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;
4210 if (r_shadow_selectedlight == NULL)
4212 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4213 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;
4214 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;
4215 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;
4216 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4217 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4218 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4219 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;
4220 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4221 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4222 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4223 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4224 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4225 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;
4226 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;
4229 void R_Shadow_EditLights_ToggleShadow_f(void)
4231 if (!r_editlights.integer)
4233 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4236 if (!r_shadow_selectedlight)
4238 Con_Print("No selected light.\n");
4241 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);
4244 void R_Shadow_EditLights_ToggleCorona_f(void)
4246 if (!r_editlights.integer)
4248 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4251 if (!r_shadow_selectedlight)
4253 Con_Print("No selected light.\n");
4256 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);
4259 void R_Shadow_EditLights_Remove_f(void)
4261 if (!r_editlights.integer)
4263 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4266 if (!r_shadow_selectedlight)
4268 Con_Print("No selected light.\n");
4271 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4272 r_shadow_selectedlight = NULL;
4275 void R_Shadow_EditLights_Help_f(void)
4278 "Documentation on r_editlights system:\n"
4280 "r_editlights : enable/disable editing mode\n"
4281 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4282 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4283 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4284 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4285 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4287 "r_editlights_help : this help\n"
4288 "r_editlights_clear : remove all lights\n"
4289 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4290 "r_editlights_save : save to .rtlights file\n"
4291 "r_editlights_spawn : create a light with default settings\n"
4292 "r_editlights_edit command : edit selected light - more documentation below\n"
4293 "r_editlights_remove : remove selected light\n"
4294 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4295 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4296 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4298 "origin x y z : set light location\n"
4299 "originx x: set x component of light location\n"
4300 "originy y: set y component of light location\n"
4301 "originz z: set z component of light location\n"
4302 "move x y z : adjust light location\n"
4303 "movex x: adjust x component of light location\n"
4304 "movey y: adjust y component of light location\n"
4305 "movez z: adjust z component of light location\n"
4306 "angles x y z : set light angles\n"
4307 "anglesx x: set x component of light angles\n"
4308 "anglesy y: set y component of light angles\n"
4309 "anglesz z: set z component of light angles\n"
4310 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4311 "radius radius : set radius (size) of light\n"
4312 "colorscale grey : multiply color of light (1 does nothing)\n"
4313 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4314 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4315 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4316 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4317 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4318 "shadows 1/0 : turn on/off shadows\n"
4319 "corona n : set corona intensity\n"
4320 "coronasize n : set corona size (0-1)\n"
4321 "ambient n : set ambient intensity (0-1)\n"
4322 "diffuse n : set diffuse intensity (0-1)\n"
4323 "specular n : set specular intensity (0-1)\n"
4324 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4325 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4326 "<nothing> : print light properties to console\n"
4330 void R_Shadow_EditLights_CopyInfo_f(void)
4332 if (!r_editlights.integer)
4334 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4337 if (!r_shadow_selectedlight)
4339 Con_Print("No selected light.\n");
4342 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4343 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4344 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4345 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4346 if (r_shadow_selectedlight->cubemapname)
4347 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4349 r_shadow_bufferlight.cubemapname[0] = 0;
4350 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4351 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4352 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4353 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4354 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4355 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4356 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4359 void R_Shadow_EditLights_PasteInfo_f(void)
4361 if (!r_editlights.integer)
4363 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4366 if (!r_shadow_selectedlight)
4368 Con_Print("No selected light.\n");
4371 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);
4374 void R_Shadow_EditLights_Init(void)
4376 Cvar_RegisterVariable(&r_editlights);
4377 Cvar_RegisterVariable(&r_editlights_cursordistance);
4378 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4379 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4380 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4381 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4382 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4383 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4384 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)");
4385 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4386 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4387 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4388 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)");
4389 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4390 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4391 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4392 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4393 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4394 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4395 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)");