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, qboolean generatenormals, qboolean generatetangents);
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, false, false);
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, false, true);
1702 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1703 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1704 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1705 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1706 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1707 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1708 GL_LockArrays(0, 0);
1712 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)
1717 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1719 // colorscale accounts for how much we multiply the brightness
1722 // mult is how many times the final pass of the lighting will be
1723 // performed to get more brightness than otherwise possible.
1725 // Limit mult to 64 for sanity sake.
1726 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1728 // 3 3D combine path (Geforce3, Radeon 8500)
1729 memset(&m, 0, sizeof(m));
1730 m.pointer_vertex = rsurface_vertex3f;
1731 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1733 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1734 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1736 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1737 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1739 m.tex[1] = R_GetTexture(basetexture);
1740 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1741 m.texmatrix[1] = texture->currenttexmatrix;
1742 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1744 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1745 m.texmatrix[2] = r_shadow_entitytolight;
1747 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1748 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1750 GL_BlendFunc(GL_ONE, GL_ONE);
1752 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1754 // 2 3D combine path (Geforce3, original Radeon)
1755 memset(&m, 0, sizeof(m));
1756 m.pointer_vertex = rsurface_vertex3f;
1757 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1759 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1760 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1762 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1763 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1765 m.tex[1] = R_GetTexture(basetexture);
1766 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1767 m.texmatrix[1] = texture->currenttexmatrix;
1768 GL_BlendFunc(GL_ONE, GL_ONE);
1770 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1772 // 4 2D combine path (Geforce3, Radeon 8500)
1773 memset(&m, 0, sizeof(m));
1774 m.pointer_vertex = rsurface_vertex3f;
1775 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1777 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1778 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1780 m.pointer_texcoord[0] = varray_texcoord2f[0];
1781 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1783 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1785 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1786 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1788 m.pointer_texcoord[1] = varray_texcoord2f[1];
1789 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1791 m.tex[2] = R_GetTexture(basetexture);
1792 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1793 m.texmatrix[2] = texture->currenttexmatrix;
1794 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1796 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1798 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1799 m.texmatrix[3] = r_shadow_entitytolight;
1801 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1802 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1805 GL_BlendFunc(GL_ONE, GL_ONE);
1807 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1809 // 3 2D combine path (Geforce3, original Radeon)
1810 memset(&m, 0, sizeof(m));
1811 m.pointer_vertex = rsurface_vertex3f;
1812 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1814 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1815 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1817 m.pointer_texcoord[0] = varray_texcoord2f[0];
1818 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1820 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1822 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1823 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1825 m.pointer_texcoord[1] = varray_texcoord2f[1];
1826 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1828 m.tex[2] = R_GetTexture(basetexture);
1829 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1830 m.texmatrix[2] = texture->currenttexmatrix;
1831 GL_BlendFunc(GL_ONE, GL_ONE);
1835 // 2/2/2 2D combine path (any dot3 card)
1836 memset(&m, 0, sizeof(m));
1837 m.pointer_vertex = rsurface_vertex3f;
1838 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1840 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1841 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1843 m.pointer_texcoord[0] = varray_texcoord2f[0];
1844 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1846 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1848 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1849 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1851 m.pointer_texcoord[1] = varray_texcoord2f[1];
1852 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1855 GL_ColorMask(0,0,0,1);
1856 GL_BlendFunc(GL_ONE, GL_ZERO);
1857 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1858 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1859 GL_LockArrays(0, 0);
1861 memset(&m, 0, sizeof(m));
1862 m.pointer_vertex = rsurface_vertex3f;
1863 m.tex[0] = R_GetTexture(basetexture);
1864 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1865 m.texmatrix[0] = texture->currenttexmatrix;
1866 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1868 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1870 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1871 m.texmatrix[1] = r_shadow_entitytolight;
1873 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1874 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1877 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1879 // this final code is shared
1881 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1882 VectorScale(lightcolorbase, colorscale, color2);
1883 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1884 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1886 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1887 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1889 GL_LockArrays(0, 0);
1892 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)
1897 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1899 // colorscale accounts for how much we multiply the brightness
1902 // mult is how many times the final pass of the lighting will be
1903 // performed to get more brightness than otherwise possible.
1905 // Limit mult to 64 for sanity sake.
1906 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1908 // 3/2 3D combine path (Geforce3, Radeon 8500)
1909 memset(&m, 0, sizeof(m));
1910 m.pointer_vertex = rsurface_vertex3f;
1911 m.tex[0] = R_GetTexture(normalmaptexture);
1912 m.texcombinergb[0] = GL_REPLACE;
1913 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1914 m.texmatrix[0] = texture->currenttexmatrix;
1915 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1916 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1917 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1918 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);
1919 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1921 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1922 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1924 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1925 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1928 GL_ColorMask(0,0,0,1);
1929 GL_BlendFunc(GL_ONE, GL_ZERO);
1930 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1931 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1932 GL_LockArrays(0, 0);
1934 memset(&m, 0, sizeof(m));
1935 m.pointer_vertex = rsurface_vertex3f;
1936 m.tex[0] = R_GetTexture(basetexture);
1937 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1938 m.texmatrix[0] = texture->currenttexmatrix;
1939 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1941 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1943 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1944 m.texmatrix[1] = r_shadow_entitytolight;
1946 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1947 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1950 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1952 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1954 // 1/2/2 3D combine path (original Radeon)
1955 memset(&m, 0, sizeof(m));
1956 m.pointer_vertex = rsurface_vertex3f;
1957 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1959 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1960 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1962 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1963 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1966 GL_ColorMask(0,0,0,1);
1967 GL_BlendFunc(GL_ONE, GL_ZERO);
1968 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1969 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1970 GL_LockArrays(0, 0);
1972 memset(&m, 0, sizeof(m));
1973 m.pointer_vertex = rsurface_vertex3f;
1974 m.tex[0] = R_GetTexture(normalmaptexture);
1975 m.texcombinergb[0] = GL_REPLACE;
1976 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1977 m.texmatrix[0] = texture->currenttexmatrix;
1978 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1979 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1980 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1981 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);
1983 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1984 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1985 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1986 GL_LockArrays(0, 0);
1988 memset(&m, 0, sizeof(m));
1989 m.pointer_vertex = rsurface_vertex3f;
1990 m.tex[0] = R_GetTexture(basetexture);
1991 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1992 m.texmatrix[0] = texture->currenttexmatrix;
1993 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1995 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1997 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1998 m.texmatrix[1] = r_shadow_entitytolight;
2000 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2001 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2004 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2006 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
2008 // 2/2 3D combine path (original Radeon)
2009 memset(&m, 0, sizeof(m));
2010 m.pointer_vertex = rsurface_vertex3f;
2011 m.tex[0] = R_GetTexture(normalmaptexture);
2012 m.texcombinergb[0] = GL_REPLACE;
2013 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2014 m.texmatrix[0] = texture->currenttexmatrix;
2015 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2016 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2017 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2018 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);
2020 GL_ColorMask(0,0,0,1);
2021 GL_BlendFunc(GL_ONE, GL_ZERO);
2022 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2023 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2024 GL_LockArrays(0, 0);
2026 memset(&m, 0, sizeof(m));
2027 m.pointer_vertex = rsurface_vertex3f;
2028 m.tex[0] = R_GetTexture(basetexture);
2029 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2030 m.texmatrix[0] = texture->currenttexmatrix;
2031 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2033 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2034 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2036 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2037 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2039 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2041 else if (r_textureunits.integer >= 4)
2043 // 4/2 2D combine path (Geforce3, Radeon 8500)
2044 memset(&m, 0, sizeof(m));
2045 m.pointer_vertex = rsurface_vertex3f;
2046 m.tex[0] = R_GetTexture(normalmaptexture);
2047 m.texcombinergb[0] = GL_REPLACE;
2048 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2049 m.texmatrix[0] = texture->currenttexmatrix;
2050 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2051 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2052 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2053 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);
2054 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2056 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2057 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2059 m.pointer_texcoord[2] = varray_texcoord2f[2];
2060 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2062 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2064 m.pointer_texcoord3f[3] = rsurface_vertex3f;
2065 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2067 m.pointer_texcoord[3] = varray_texcoord2f[3];
2068 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2071 GL_ColorMask(0,0,0,1);
2072 GL_BlendFunc(GL_ONE, GL_ZERO);
2073 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2074 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2075 GL_LockArrays(0, 0);
2077 memset(&m, 0, sizeof(m));
2078 m.pointer_vertex = rsurface_vertex3f;
2079 m.tex[0] = R_GetTexture(basetexture);
2080 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2081 m.texmatrix[0] = texture->currenttexmatrix;
2082 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2084 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2086 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2087 m.texmatrix[1] = r_shadow_entitytolight;
2089 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2090 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2093 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2097 // 2/2/2 2D combine path (any dot3 card)
2098 memset(&m, 0, sizeof(m));
2099 m.pointer_vertex = rsurface_vertex3f;
2100 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2102 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2103 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2105 m.pointer_texcoord[0] = varray_texcoord2f[0];
2106 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2108 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2110 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2111 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2113 m.pointer_texcoord[1] = varray_texcoord2f[1];
2114 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2117 GL_ColorMask(0,0,0,1);
2118 GL_BlendFunc(GL_ONE, GL_ZERO);
2119 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2120 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2121 GL_LockArrays(0, 0);
2123 memset(&m, 0, sizeof(m));
2124 m.pointer_vertex = rsurface_vertex3f;
2125 m.tex[0] = R_GetTexture(normalmaptexture);
2126 m.texcombinergb[0] = GL_REPLACE;
2127 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2128 m.texmatrix[0] = texture->currenttexmatrix;
2129 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2130 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2131 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2132 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);
2134 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2135 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2136 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2137 GL_LockArrays(0, 0);
2139 memset(&m, 0, sizeof(m));
2140 m.pointer_vertex = rsurface_vertex3f;
2141 m.tex[0] = R_GetTexture(basetexture);
2142 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2143 m.texmatrix[0] = texture->currenttexmatrix;
2144 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2146 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2148 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2149 m.texmatrix[1] = r_shadow_entitytolight;
2151 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2152 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2155 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2157 // this final code is shared
2159 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2160 VectorScale(lightcolorbase, colorscale, color2);
2161 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2162 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2164 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2165 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2167 GL_LockArrays(0, 0);
2170 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)
2175 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2176 // FIXME: detect blendsquare!
2177 //if (!gl_support_blendsquare)
2180 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2182 // 2/0/0/1/2 3D combine blendsquare path
2183 memset(&m, 0, sizeof(m));
2184 m.pointer_vertex = rsurface_vertex3f;
2185 m.tex[0] = R_GetTexture(normalmaptexture);
2186 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2187 m.texmatrix[0] = texture->currenttexmatrix;
2188 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2189 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2190 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2191 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);
2193 GL_ColorMask(0,0,0,1);
2194 // this squares the result
2195 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2196 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2197 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2198 GL_LockArrays(0, 0);
2200 memset(&m, 0, sizeof(m));
2201 m.pointer_vertex = rsurface_vertex3f;
2203 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2204 // square alpha in framebuffer a few times to make it shiny
2205 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2206 // these comments are a test run through this math for intensity 0.5
2207 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2208 // 0.25 * 0.25 = 0.0625 (this is another pass)
2209 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2210 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2211 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2212 GL_LockArrays(0, 0);
2214 memset(&m, 0, sizeof(m));
2215 m.pointer_vertex = rsurface_vertex3f;
2216 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2218 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2219 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2221 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2222 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2225 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2226 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2227 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2228 GL_LockArrays(0, 0);
2230 memset(&m, 0, sizeof(m));
2231 m.pointer_vertex = rsurface_vertex3f;
2232 m.tex[0] = R_GetTexture(glosstexture);
2233 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2234 m.texmatrix[0] = texture->currenttexmatrix;
2235 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2237 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2239 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2240 m.texmatrix[1] = r_shadow_entitytolight;
2242 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2243 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2246 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2248 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2250 // 2/0/0/2 3D combine blendsquare path
2251 memset(&m, 0, sizeof(m));
2252 m.pointer_vertex = rsurface_vertex3f;
2253 m.tex[0] = R_GetTexture(normalmaptexture);
2254 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2255 m.texmatrix[0] = texture->currenttexmatrix;
2256 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2257 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2258 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2259 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);
2261 GL_ColorMask(0,0,0,1);
2262 // this squares the result
2263 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2264 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2265 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2266 GL_LockArrays(0, 0);
2268 memset(&m, 0, sizeof(m));
2269 m.pointer_vertex = rsurface_vertex3f;
2271 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2272 // square alpha in framebuffer a few times to make it shiny
2273 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2274 // these comments are a test run through this math for intensity 0.5
2275 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2276 // 0.25 * 0.25 = 0.0625 (this is another pass)
2277 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2278 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2279 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2280 GL_LockArrays(0, 0);
2282 memset(&m, 0, sizeof(m));
2283 m.pointer_vertex = rsurface_vertex3f;
2284 m.tex[0] = R_GetTexture(glosstexture);
2285 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2286 m.texmatrix[0] = texture->currenttexmatrix;
2287 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2289 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2290 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2292 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2293 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2295 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2299 // 2/0/0/2/2 2D combine blendsquare path
2300 memset(&m, 0, sizeof(m));
2301 m.pointer_vertex = rsurface_vertex3f;
2302 m.tex[0] = R_GetTexture(normalmaptexture);
2303 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2304 m.texmatrix[0] = texture->currenttexmatrix;
2305 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2306 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2307 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2308 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);
2310 GL_ColorMask(0,0,0,1);
2311 // this squares the result
2312 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2313 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2314 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2315 GL_LockArrays(0, 0);
2317 memset(&m, 0, sizeof(m));
2318 m.pointer_vertex = rsurface_vertex3f;
2320 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2321 // square alpha in framebuffer a few times to make it shiny
2322 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2323 // these comments are a test run through this math for intensity 0.5
2324 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2325 // 0.25 * 0.25 = 0.0625 (this is another pass)
2326 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2327 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2328 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2329 GL_LockArrays(0, 0);
2331 memset(&m, 0, sizeof(m));
2332 m.pointer_vertex = rsurface_vertex3f;
2333 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2335 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2336 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2338 m.pointer_texcoord[0] = varray_texcoord2f[0];
2339 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2341 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2343 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2344 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2346 m.pointer_texcoord[1] = varray_texcoord2f[1];
2347 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2350 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2351 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2352 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2353 GL_LockArrays(0, 0);
2355 memset(&m, 0, sizeof(m));
2356 m.pointer_vertex = rsurface_vertex3f;
2357 m.tex[0] = R_GetTexture(glosstexture);
2358 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2359 m.texmatrix[0] = texture->currenttexmatrix;
2360 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2362 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2364 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2365 m.texmatrix[1] = r_shadow_entitytolight;
2367 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2368 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2371 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2374 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2375 VectorScale(lightcolorbase, colorscale, color2);
2376 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2377 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2379 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2380 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2382 GL_LockArrays(0, 0);
2385 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)
2387 // ARB path (any Geforce, any Radeon)
2388 int surfacelistindex;
2389 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
2390 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
2391 qboolean dospecular = specularscale > 0;
2392 if (!doambient && !dodiffuse && !dospecular)
2394 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2396 const msurface_t *surface = surfacelist[surfacelistindex];
2397 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
2399 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
2401 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2405 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
2407 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2412 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
2414 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2417 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(ent, texture, surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
2421 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
2424 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2425 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
2426 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
2431 // due to low fillrate on the cards this vertex lighting path is
2432 // designed for, we manually cull all triangles that do not
2433 // contain a lit vertex
2436 int newnumtriangles;
2438 int newelements[3072];
2440 newnumtriangles = 0;
2442 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
2444 if (newnumtriangles >= 1024)
2446 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2447 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
2448 GL_LockArrays(0, 0);
2449 newnumtriangles = 0;
2452 if (VectorLength2(varray_color4f + e[0] * 4) + VectorLength2(varray_color4f + e[1] * 4) + VectorLength2(varray_color4f + e[2] * 4) >= 0.01)
2462 if (newnumtriangles >= 1)
2464 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2465 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
2466 GL_LockArrays(0, 0);
2472 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
2473 if (VectorLength2(c))
2477 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2478 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2479 GL_LockArrays(0, 0);
2481 // now reduce the intensity for the next overbright pass
2482 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
2484 c[0] = max(0, c[0] - 1);
2485 c[1] = max(0, c[1] - 1);
2486 c[2] = max(0, c[2] - 1);
2491 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)
2493 int surfacelistindex;
2494 float ambientcolorbase[3], diffusecolorbase[3];
2495 float ambientcolorpants[3], diffusecolorpants[3];
2496 float ambientcolorshirt[3], diffusecolorshirt[3];
2498 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
2499 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
2500 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
2501 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
2502 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
2503 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
2504 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2505 memset(&m, 0, sizeof(m));
2506 m.tex[0] = R_GetTexture(basetexture);
2507 if (r_textureunits.integer >= 2)
2510 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2512 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2514 m.pointer_texcoord[1] = varray_texcoord2f[1];
2515 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2517 if (r_textureunits.integer >= 3)
2519 // Geforce3/Radeon class but not using dot3
2520 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2522 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2524 m.pointer_texcoord[2] = varray_texcoord2f[2];
2525 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2529 m.pointer_color = varray_color4f;
2531 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2533 const msurface_t *surface = surfacelist[surfacelistindex];
2534 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, true, false);
2535 // OpenGL 1.1 path (anything)
2536 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2537 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
2538 if (r_textureunits.integer >= 2)
2542 R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
2544 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2546 if (r_textureunits.integer >= 3)
2548 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2550 R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
2552 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2556 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2557 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorbase, ambientcolorbase);
2560 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2561 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorpants, ambientcolorpants);
2565 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2566 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorshirt, ambientcolorshirt);
2571 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
2573 // FIXME: support MATERIALFLAG_NODEPTHTEST
2574 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2575 rtexture_t *basetexture;
2576 rtexture_t *pantstexture;
2577 rtexture_t *shirttexture;
2578 rtexture_t *glosstexture;
2579 float specularscale;
2580 qboolean dopants, doshirt;
2581 glosstexture = r_texture_black;
2583 if (r_shadow_gloss.integer > 0)
2585 if (texture->skin.gloss)
2587 if (r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
2589 glosstexture = texture->skin.gloss;
2590 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
2595 if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
2597 glosstexture = r_texture_white;
2598 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
2602 // calculate colors to render this texture with
2603 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
2604 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
2605 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
2606 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2608 if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
2609 qglDisable(GL_CULL_FACE);
2611 qglEnable(GL_CULL_FACE);
2612 dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
2613 doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2614 if (dopants + doshirt)
2618 lightcolorpants[0] = lightcolorbase[0] * ent->colormap_pantscolor[0];
2619 lightcolorpants[1] = lightcolorbase[1] * ent->colormap_pantscolor[1];
2620 lightcolorpants[2] = lightcolorbase[2] * ent->colormap_pantscolor[2];
2624 pantstexture = r_texture_black;
2625 VectorClear(lightcolorpants);
2629 shirttexture = texture->skin.shirt;
2630 lightcolorshirt[0] = lightcolorbase[0] * ent->colormap_shirtcolor[0];
2631 lightcolorshirt[1] = lightcolorbase[1] * ent->colormap_shirtcolor[1];
2632 lightcolorshirt[2] = lightcolorbase[2] * ent->colormap_shirtcolor[2];
2636 shirttexture = r_texture_black;
2637 VectorClear(lightcolorshirt);
2639 switch (r_shadow_rendermode)
2641 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2642 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);
2644 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2645 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);
2647 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2648 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);
2650 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2651 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);
2654 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2660 basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
2661 switch (r_shadow_rendermode)
2663 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2664 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);
2666 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2667 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);
2669 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2670 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);
2672 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2673 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);
2676 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2682 void R_RTLight_Update(dlight_t *light, int isstatic)
2686 rtlight_t *rtlight = &light->rtlight;
2687 R_RTLight_Uncompile(rtlight);
2688 memset(rtlight, 0, sizeof(*rtlight));
2690 VectorCopy(light->origin, rtlight->shadoworigin);
2691 VectorCopy(light->color, rtlight->color);
2692 rtlight->radius = light->radius;
2693 //rtlight->cullradius = rtlight->radius;
2694 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2695 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2696 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2697 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2698 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2699 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2700 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2701 rtlight->cubemapname[0] = 0;
2702 if (light->cubemapname[0])
2703 strcpy(rtlight->cubemapname, light->cubemapname);
2704 else if (light->cubemapnum > 0)
2705 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2706 rtlight->shadow = light->shadow;
2707 rtlight->corona = light->corona;
2708 rtlight->style = light->style;
2709 rtlight->isstatic = isstatic;
2710 rtlight->coronasizescale = light->coronasizescale;
2711 rtlight->ambientscale = light->ambientscale;
2712 rtlight->diffusescale = light->diffusescale;
2713 rtlight->specularscale = light->specularscale;
2714 rtlight->flags = light->flags;
2715 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2716 // ConcatScale won't work here because this needs to scale rotate and
2717 // translate, not just rotate
2718 scale = 1.0f / rtlight->radius;
2719 for (k = 0;k < 3;k++)
2720 for (j = 0;j < 4;j++)
2721 rtlight->matrix_worldtolight.m[k][j] *= scale;
2723 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2724 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2725 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2726 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2729 // compiles rtlight geometry
2730 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2731 void R_RTLight_Compile(rtlight_t *rtlight)
2733 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2734 entity_render_t *ent = r_refdef.worldentity;
2735 model_t *model = r_refdef.worldmodel;
2736 unsigned char *data;
2738 // compile the light
2739 rtlight->compiled = true;
2740 rtlight->static_numleafs = 0;
2741 rtlight->static_numleafpvsbytes = 0;
2742 rtlight->static_leaflist = NULL;
2743 rtlight->static_leafpvs = NULL;
2744 rtlight->static_numsurfaces = 0;
2745 rtlight->static_surfacelist = NULL;
2746 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2747 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2748 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2749 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2750 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2751 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2753 if (model && model->GetLightInfo)
2755 // this variable must be set for the CompileShadowVolume code
2756 r_shadow_compilingrtlight = rtlight;
2757 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2758 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);
2759 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2760 data = (unsigned char *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2761 rtlight->static_numleafs = numleafs;
2762 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2763 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2764 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2765 rtlight->static_numsurfaces = numsurfaces;
2766 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2768 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2769 if (numleafpvsbytes)
2770 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2772 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2773 if (model->CompileShadowVolume && rtlight->shadow)
2774 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2775 // now we're done compiling the rtlight
2776 r_shadow_compilingrtlight = NULL;
2780 // use smallest available cullradius - box radius or light radius
2781 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2782 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2786 if (rtlight->static_meshchain_shadow)
2789 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2792 shadowtris += mesh->numtriangles;
2796 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);
2799 void R_RTLight_Uncompile(rtlight_t *rtlight)
2801 if (rtlight->compiled)
2803 if (rtlight->static_meshchain_shadow)
2804 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2805 rtlight->static_meshchain_shadow = NULL;
2806 // these allocations are grouped
2807 if (rtlight->static_leaflist)
2808 Mem_Free(rtlight->static_leaflist);
2809 rtlight->static_numleafs = 0;
2810 rtlight->static_numleafpvsbytes = 0;
2811 rtlight->static_leaflist = NULL;
2812 rtlight->static_leafpvs = NULL;
2813 rtlight->static_numsurfaces = 0;
2814 rtlight->static_surfacelist = NULL;
2815 rtlight->compiled = false;
2819 void R_Shadow_UncompileWorldLights(void)
2822 for (light = r_shadow_worldlightchain;light;light = light->next)
2823 R_RTLight_Uncompile(&light->rtlight);
2826 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2828 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2829 vec_t relativeshadowradius;
2830 if (ent == r_refdef.worldentity)
2832 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2835 R_Mesh_Matrix(&ent->matrix);
2836 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2838 renderstats.lights_shadowtriangles += mesh->numtriangles;
2839 R_Mesh_VertexPointer(mesh->vertex3f);
2840 GL_LockArrays(0, mesh->numverts);
2841 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2843 // decrement stencil if backface is behind depthbuffer
2844 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2845 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2846 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2847 // increment stencil if frontface is behind depthbuffer
2848 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2849 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2851 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2852 GL_LockArrays(0, 0);
2855 else if (numsurfaces)
2857 R_Mesh_Matrix(&ent->matrix);
2858 ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2863 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2864 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2865 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2866 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2867 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2868 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2869 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2870 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2871 R_Mesh_Matrix(&ent->matrix);
2872 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2876 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2878 // set up properties for rendering light onto this entity
2879 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2880 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2881 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2882 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2883 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2884 R_Mesh_Matrix(&ent->matrix);
2887 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2889 R_Shadow_SetupEntityLight(ent);
2890 if (ent == r_refdef.worldentity)
2891 ent->model->DrawLight(ent, numsurfaces, surfacelist);
2893 ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
2896 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2900 int numleafs, numsurfaces;
2901 int *leaflist, *surfacelist;
2902 unsigned char *leafpvs;
2903 int numlightentities;
2904 int numshadowentities;
2905 entity_render_t *lightentities[MAX_EDICTS];
2906 entity_render_t *shadowentities[MAX_EDICTS];
2908 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2909 // skip lights that are basically invisible (color 0 0 0)
2910 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2913 // loading is done before visibility checks because loading should happen
2914 // all at once at the start of a level, not when it stalls gameplay.
2915 // (especially important to benchmarks)
2917 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2918 R_RTLight_Compile(rtlight);
2920 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2922 // look up the light style value at this time
2923 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2924 VectorScale(rtlight->color, f, rtlight->currentcolor);
2926 if (rtlight->selected)
2928 f = 2 + sin(realtime * M_PI * 4.0);
2929 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2933 // if lightstyle is currently off, don't draw the light
2934 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2937 // if the light box is offscreen, skip it
2938 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2941 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2943 // compiled light, world available and can receive realtime lighting
2944 // retrieve leaf information
2945 numleafs = rtlight->static_numleafs;
2946 leaflist = rtlight->static_leaflist;
2947 leafpvs = rtlight->static_leafpvs;
2948 numsurfaces = rtlight->static_numsurfaces;
2949 surfacelist = rtlight->static_surfacelist;
2951 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2953 // dynamic light, world available and can receive realtime lighting
2954 // calculate lit surfaces and leafs
2955 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2956 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);
2957 leaflist = r_shadow_buffer_leaflist;
2958 leafpvs = r_shadow_buffer_leafpvs;
2959 surfacelist = r_shadow_buffer_surfacelist;
2960 // if the reduced leaf bounds are offscreen, skip it
2961 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2973 // check if light is illuminating any visible leafs
2976 for (i = 0;i < numleafs;i++)
2977 if (r_worldleafvisible[leaflist[i]])
2982 // set up a scissor rectangle for this light
2983 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2986 // make a list of lit entities and shadow casting entities
2987 numlightentities = 0;
2988 numshadowentities = 0;
2989 // don't count the world unless some surfaces are actually lit
2992 lightentities[numlightentities++] = r_refdef.worldentity;
2993 shadowentities[numshadowentities++] = r_refdef.worldentity;
2995 // add dynamic entities that are lit by the light
2996 if (r_drawentities.integer)
2998 for (i = 0;i < r_refdef.numentities;i++)
3000 entity_render_t *ent = r_refdef.entities[i];
3001 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
3003 && !(ent->flags & RENDER_TRANSPARENT)
3004 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
3006 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3007 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
3008 shadowentities[numshadowentities++] = ent;
3009 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
3010 lightentities[numlightentities++] = ent;
3015 // return if there's nothing at all to light
3016 if (!numlightentities)
3019 // don't let sound skip if going slow
3020 if (r_refdef.extraupdate)
3023 // make this the active rtlight for rendering purposes
3024 R_Shadow_RenderMode_ActiveLight(rtlight);
3025 // count this light in the r_speeds
3026 renderstats.lights++;
3029 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
3031 // draw stencil shadow volumes to mask off pixels that are in shadow
3032 // so that they won't receive lighting
3036 R_Shadow_RenderMode_StencilShadowVolumes();
3037 for (i = 0;i < numshadowentities;i++)
3038 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
3041 // optionally draw visible shape of the shadow volumes
3042 // for performance analysis by level designers
3043 if (r_showshadowvolumes.integer)
3045 R_Shadow_RenderMode_VisibleShadowVolumes();
3046 for (i = 0;i < numshadowentities;i++)
3047 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
3051 if (numlightentities)
3053 // draw lighting in the unmasked areas
3054 R_Shadow_RenderMode_Lighting(usestencil, false);
3055 for (i = 0;i < numlightentities;i++)
3056 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3058 // optionally draw the illuminated areas
3059 // for performance analysis by level designers
3060 if (r_showlighting.integer)
3062 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
3063 for (i = 0;i < numlightentities;i++)
3064 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3069 void R_ShadowVolumeLighting(qboolean visible)
3074 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3075 R_Shadow_EditLights_Reload_f();
3077 R_Shadow_RenderMode_Begin();
3079 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3080 if (r_shadow_debuglight.integer >= 0)
3082 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3083 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3084 R_DrawRTLight(&light->rtlight, visible);
3087 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3088 if (light->flags & flag)
3089 R_DrawRTLight(&light->rtlight, visible);
3091 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3092 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
3094 R_Shadow_RenderMode_End();
3097 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3098 typedef struct suffixinfo_s
3101 qboolean flipx, flipy, flipdiagonal;
3104 static suffixinfo_t suffix[3][6] =
3107 {"px", false, false, false},
3108 {"nx", false, false, false},
3109 {"py", false, false, false},
3110 {"ny", false, false, false},
3111 {"pz", false, false, false},
3112 {"nz", false, false, false}
3115 {"posx", false, false, false},
3116 {"negx", false, false, false},
3117 {"posy", false, false, false},
3118 {"negy", false, false, false},
3119 {"posz", false, false, false},
3120 {"negz", false, false, false}
3123 {"rt", true, false, true},
3124 {"lf", false, true, true},
3125 {"ft", true, true, false},
3126 {"bk", false, false, false},
3127 {"up", true, false, true},
3128 {"dn", true, false, true}
3132 static int componentorder[4] = {0, 1, 2, 3};
3134 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3136 int i, j, cubemapsize;
3137 unsigned char *cubemappixels, *image_rgba;
3138 rtexture_t *cubemaptexture;
3140 // must start 0 so the first loadimagepixels has no requested width/height
3142 cubemappixels = NULL;
3143 cubemaptexture = NULL;
3144 // keep trying different suffix groups (posx, px, rt) until one loads
3145 for (j = 0;j < 3 && !cubemappixels;j++)
3147 // load the 6 images in the suffix group
3148 for (i = 0;i < 6;i++)
3150 // generate an image name based on the base and and suffix
3151 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3153 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3155 // an image loaded, make sure width and height are equal
3156 if (image_width == image_height)
3158 // if this is the first image to load successfully, allocate the cubemap memory
3159 if (!cubemappixels && image_width >= 1)
3161 cubemapsize = image_width;
3162 // note this clears to black, so unavailable sides are black
3163 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3165 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3167 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);
3170 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3172 Mem_Free(image_rgba);
3176 // if a cubemap loaded, upload it
3179 if (!r_shadow_filters_texturepool)
3180 r_shadow_filters_texturepool = R_AllocTexturePool();
3181 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3182 Mem_Free(cubemappixels);
3186 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3187 for (j = 0;j < 3;j++)
3188 for (i = 0;i < 6;i++)
3189 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3190 Con_Print(" and was unable to find any of them.\n");
3192 return cubemaptexture;
3195 rtexture_t *R_Shadow_Cubemap(const char *basename)
3198 for (i = 0;i < numcubemaps;i++)
3199 if (!strcasecmp(cubemaps[i].basename, basename))
3200 return cubemaps[i].texture;
3201 if (i >= MAX_CUBEMAPS)
3202 return r_texture_whitecube;
3204 strcpy(cubemaps[i].basename, basename);
3205 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3206 if (!cubemaps[i].texture)
3207 cubemaps[i].texture = r_texture_whitecube;
3208 return cubemaps[i].texture;
3211 void R_Shadow_FreeCubemaps(void)
3214 R_FreeTexturePool(&r_shadow_filters_texturepool);
3217 dlight_t *R_Shadow_NewWorldLight(void)
3220 light = (dlight_t *)Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3221 light->next = r_shadow_worldlightchain;
3222 r_shadow_worldlightchain = light;
3226 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)
3228 VectorCopy(origin, light->origin);
3229 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3230 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3231 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3232 light->color[0] = max(color[0], 0);
3233 light->color[1] = max(color[1], 0);
3234 light->color[2] = max(color[2], 0);
3235 light->radius = max(radius, 0);
3236 light->style = style;
3237 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3239 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3242 light->shadow = shadowenable;
3243 light->corona = corona;
3246 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3247 light->coronasizescale = coronasizescale;
3248 light->ambientscale = ambientscale;
3249 light->diffusescale = diffusescale;
3250 light->specularscale = specularscale;
3251 light->flags = flags;
3252 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3254 R_RTLight_Update(light, true);
3257 void R_Shadow_FreeWorldLight(dlight_t *light)
3259 dlight_t **lightpointer;
3260 R_RTLight_Uncompile(&light->rtlight);
3261 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3262 if (*lightpointer != light)
3263 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3264 *lightpointer = light->next;
3268 void R_Shadow_ClearWorldLights(void)
3270 while (r_shadow_worldlightchain)
3271 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3272 r_shadow_selectedlight = NULL;
3273 R_Shadow_FreeCubemaps();
3276 void R_Shadow_SelectLight(dlight_t *light)
3278 if (r_shadow_selectedlight)
3279 r_shadow_selectedlight->selected = false;
3280 r_shadow_selectedlight = light;
3281 if (r_shadow_selectedlight)
3282 r_shadow_selectedlight->selected = true;
3285 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
3287 float scale = r_editlights_cursorgrid.value * 0.5f;
3288 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);
3291 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
3294 const dlight_t *light = (dlight_t *)ent;
3296 if (light->selected)
3297 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3300 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);
3303 void R_Shadow_DrawLightSprites(void)
3308 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3309 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, i % NUMCROSSHAIRS, &light->rtlight);
3310 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3313 void R_Shadow_SelectLightInView(void)
3315 float bestrating, rating, temp[3];
3316 dlight_t *best, *light;
3319 for (light = r_shadow_worldlightchain;light;light = light->next)
3321 VectorSubtract(light->origin, r_vieworigin, temp);
3322 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3325 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3326 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3328 bestrating = rating;
3333 R_Shadow_SelectLight(best);
3336 void R_Shadow_LoadWorldLights(void)
3338 int n, a, style, shadow, flags;
3339 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3340 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3341 if (r_refdef.worldmodel == NULL)
3343 Con_Print("No map loaded.\n");
3346 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3347 strlcat (name, ".rtlights", sizeof (name));
3348 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3358 for (;COM_Parse(t, true) && strcmp(
3359 if (COM_Parse(t, true))
3361 if (com_token[0] == '!')
3364 origin[0] = atof(com_token+1);
3367 origin[0] = atof(com_token);
3372 while (*s && *s != '\n' && *s != '\r')
3378 // check for modifier flags
3385 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);
3388 flags = LIGHTFLAG_REALTIMEMODE;
3396 coronasizescale = 0.25f;
3398 VectorClear(angles);
3401 if (a < 9 || !strcmp(cubemapname, "\"\""))
3403 // remove quotes on cubemapname
3404 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3406 cubemapname[strlen(cubemapname)-1] = 0;
3407 strcpy(cubemapname, cubemapname + 1);
3411 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);
3414 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3422 Con_Printf("invalid rtlights file \"%s\"\n", name);
3423 Mem_Free(lightsstring);
3427 void R_Shadow_SaveWorldLights(void)
3430 size_t bufchars, bufmaxchars;
3432 char name[MAX_QPATH];
3433 char line[MAX_INPUTLINE];
3434 if (!r_shadow_worldlightchain)
3436 if (r_refdef.worldmodel == NULL)
3438 Con_Print("No map loaded.\n");
3441 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3442 strlcat (name, ".rtlights", sizeof (name));
3443 bufchars = bufmaxchars = 0;
3445 for (light = r_shadow_worldlightchain;light;light = light->next)
3447 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3448 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);
3449 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3450 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]);
3452 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);
3453 if (bufchars + strlen(line) > bufmaxchars)
3455 bufmaxchars = bufchars + strlen(line) + 2048;
3457 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3461 memcpy(buf, oldbuf, bufchars);
3467 memcpy(buf + bufchars, line, strlen(line));
3468 bufchars += strlen(line);
3472 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3477 void R_Shadow_LoadLightsFile(void)
3480 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3481 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3482 if (r_refdef.worldmodel == NULL)
3484 Con_Print("No map loaded.\n");
3487 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3488 strlcat (name, ".lights", sizeof (name));
3489 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3497 while (*s && *s != '\n' && *s != '\r')
3503 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);
3507 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);
3510 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3511 radius = bound(15, radius, 4096);
3512 VectorScale(color, (2.0f / (8388608.0f)), color);
3513 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3521 Con_Printf("invalid lights file \"%s\"\n", name);
3522 Mem_Free(lightsstring);
3526 // tyrlite/hmap2 light types in the delay field
3527 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3529 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3531 int entnum, style, islight, skin, pflags, effects, type, n;
3534 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3535 char key[256], value[MAX_INPUTLINE];
3537 if (r_refdef.worldmodel == NULL)
3539 Con_Print("No map loaded.\n");
3542 // try to load a .ent file first
3543 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3544 strlcat (key, ".ent", sizeof (key));
3545 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3546 // and if that is not found, fall back to the bsp file entity string
3548 data = r_refdef.worldmodel->brush.entities;
3551 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3553 type = LIGHTTYPE_MINUSX;
3554 origin[0] = origin[1] = origin[2] = 0;
3555 originhack[0] = originhack[1] = originhack[2] = 0;
3556 angles[0] = angles[1] = angles[2] = 0;
3557 color[0] = color[1] = color[2] = 1;
3558 light[0] = light[1] = light[2] = 1;light[3] = 300;
3559 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3569 if (!COM_ParseToken(&data, false))
3571 if (com_token[0] == '}')
3572 break; // end of entity
3573 if (com_token[0] == '_')
3574 strcpy(key, com_token + 1);
3576 strcpy(key, com_token);
3577 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3578 key[strlen(key)-1] = 0;
3579 if (!COM_ParseToken(&data, false))
3581 strcpy(value, com_token);
3583 // now that we have the key pair worked out...
3584 if (!strcmp("light", key))
3586 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3590 light[0] = vec[0] * (1.0f / 256.0f);
3591 light[1] = vec[0] * (1.0f / 256.0f);
3592 light[2] = vec[0] * (1.0f / 256.0f);
3598 light[0] = vec[0] * (1.0f / 255.0f);
3599 light[1] = vec[1] * (1.0f / 255.0f);
3600 light[2] = vec[2] * (1.0f / 255.0f);
3604 else if (!strcmp("delay", key))
3606 else if (!strcmp("origin", key))
3607 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3608 else if (!strcmp("angle", key))
3609 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3610 else if (!strcmp("angles", key))
3611 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3612 else if (!strcmp("color", key))
3613 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3614 else if (!strcmp("wait", key))
3615 fadescale = atof(value);
3616 else if (!strcmp("classname", key))
3618 if (!strncmp(value, "light", 5))
3621 if (!strcmp(value, "light_fluoro"))
3626 overridecolor[0] = 1;
3627 overridecolor[1] = 1;
3628 overridecolor[2] = 1;
3630 if (!strcmp(value, "light_fluorospark"))
3635 overridecolor[0] = 1;
3636 overridecolor[1] = 1;
3637 overridecolor[2] = 1;
3639 if (!strcmp(value, "light_globe"))
3644 overridecolor[0] = 1;
3645 overridecolor[1] = 0.8;
3646 overridecolor[2] = 0.4;
3648 if (!strcmp(value, "light_flame_large_yellow"))
3653 overridecolor[0] = 1;
3654 overridecolor[1] = 0.5;
3655 overridecolor[2] = 0.1;
3657 if (!strcmp(value, "light_flame_small_yellow"))
3662 overridecolor[0] = 1;
3663 overridecolor[1] = 0.5;
3664 overridecolor[2] = 0.1;
3666 if (!strcmp(value, "light_torch_small_white"))
3671 overridecolor[0] = 1;
3672 overridecolor[1] = 0.5;
3673 overridecolor[2] = 0.1;
3675 if (!strcmp(value, "light_torch_small_walltorch"))
3680 overridecolor[0] = 1;
3681 overridecolor[1] = 0.5;
3682 overridecolor[2] = 0.1;
3686 else if (!strcmp("style", key))
3687 style = atoi(value);
3688 else if (!strcmp("skin", key))
3689 skin = (int)atof(value);
3690 else if (!strcmp("pflags", key))
3691 pflags = (int)atof(value);
3692 else if (!strcmp("effects", key))
3693 effects = (int)atof(value);
3694 else if (r_refdef.worldmodel->type == mod_brushq3)
3696 if (!strcmp("scale", key))
3697 lightscale = atof(value);
3698 if (!strcmp("fade", key))
3699 fadescale = atof(value);
3704 if (lightscale <= 0)
3708 if (color[0] == color[1] && color[0] == color[2])
3710 color[0] *= overridecolor[0];
3711 color[1] *= overridecolor[1];
3712 color[2] *= overridecolor[2];
3714 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3715 color[0] = color[0] * light[0];
3716 color[1] = color[1] * light[1];
3717 color[2] = color[2] * light[2];
3720 case LIGHTTYPE_MINUSX:
3722 case LIGHTTYPE_RECIPX:
3724 VectorScale(color, (1.0f / 16.0f), color);
3726 case LIGHTTYPE_RECIPXX:
3728 VectorScale(color, (1.0f / 16.0f), color);
3731 case LIGHTTYPE_NONE:
3735 case LIGHTTYPE_MINUSXX:
3738 VectorAdd(origin, originhack, origin);
3740 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);
3743 Mem_Free(entfiledata);
3747 void R_Shadow_SetCursorLocationForView(void)
3750 vec3_t dest, endpos;
3752 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3753 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3754 if (trace.fraction < 1)
3756 dist = trace.fraction * r_editlights_cursordistance.value;
3757 push = r_editlights_cursorpushback.value;
3761 VectorMA(trace.endpos, push, r_viewforward, endpos);
3762 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3766 VectorClear( endpos );
3768 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3769 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3770 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3773 void R_Shadow_UpdateWorldLightSelection(void)
3775 if (r_editlights.integer)
3777 R_Shadow_SetCursorLocationForView();
3778 R_Shadow_SelectLightInView();
3779 R_Shadow_DrawLightSprites();
3782 R_Shadow_SelectLight(NULL);
3785 void R_Shadow_EditLights_Clear_f(void)
3787 R_Shadow_ClearWorldLights();
3790 void R_Shadow_EditLights_Reload_f(void)
3792 if (!r_refdef.worldmodel)
3794 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3795 R_Shadow_ClearWorldLights();
3796 R_Shadow_LoadWorldLights();
3797 if (r_shadow_worldlightchain == NULL)
3799 R_Shadow_LoadLightsFile();
3800 if (r_shadow_worldlightchain == NULL)
3801 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3805 void R_Shadow_EditLights_Save_f(void)
3807 if (!r_refdef.worldmodel)
3809 R_Shadow_SaveWorldLights();
3812 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3814 R_Shadow_ClearWorldLights();
3815 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3818 void R_Shadow_EditLights_ImportLightsFile_f(void)
3820 R_Shadow_ClearWorldLights();
3821 R_Shadow_LoadLightsFile();
3824 void R_Shadow_EditLights_Spawn_f(void)
3827 if (!r_editlights.integer)
3829 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3832 if (Cmd_Argc() != 1)
3834 Con_Print("r_editlights_spawn does not take parameters\n");
3837 color[0] = color[1] = color[2] = 1;
3838 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3841 void R_Shadow_EditLights_Edit_f(void)
3843 vec3_t origin, angles, color;
3844 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3845 int style, shadows, flags, normalmode, realtimemode;
3846 char cubemapname[MAX_INPUTLINE];
3847 if (!r_editlights.integer)
3849 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3852 if (!r_shadow_selectedlight)
3854 Con_Print("No selected light.\n");
3857 VectorCopy(r_shadow_selectedlight->origin, origin);
3858 VectorCopy(r_shadow_selectedlight->angles, angles);
3859 VectorCopy(r_shadow_selectedlight->color, color);
3860 radius = r_shadow_selectedlight->radius;
3861 style = r_shadow_selectedlight->style;
3862 if (r_shadow_selectedlight->cubemapname)
3863 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3866 shadows = r_shadow_selectedlight->shadow;
3867 corona = r_shadow_selectedlight->corona;
3868 coronasizescale = r_shadow_selectedlight->coronasizescale;
3869 ambientscale = r_shadow_selectedlight->ambientscale;
3870 diffusescale = r_shadow_selectedlight->diffusescale;
3871 specularscale = r_shadow_selectedlight->specularscale;
3872 flags = r_shadow_selectedlight->flags;
3873 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3874 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3875 if (!strcmp(Cmd_Argv(1), "origin"))
3877 if (Cmd_Argc() != 5)
3879 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3882 origin[0] = atof(Cmd_Argv(2));
3883 origin[1] = atof(Cmd_Argv(3));
3884 origin[2] = atof(Cmd_Argv(4));
3886 else if (!strcmp(Cmd_Argv(1), "originx"))
3888 if (Cmd_Argc() != 3)
3890 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3893 origin[0] = atof(Cmd_Argv(2));
3895 else if (!strcmp(Cmd_Argv(1), "originy"))
3897 if (Cmd_Argc() != 3)
3899 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3902 origin[1] = atof(Cmd_Argv(2));
3904 else if (!strcmp(Cmd_Argv(1), "originz"))
3906 if (Cmd_Argc() != 3)
3908 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3911 origin[2] = atof(Cmd_Argv(2));
3913 else if (!strcmp(Cmd_Argv(1), "move"))
3915 if (Cmd_Argc() != 5)
3917 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3920 origin[0] += atof(Cmd_Argv(2));
3921 origin[1] += atof(Cmd_Argv(3));
3922 origin[2] += atof(Cmd_Argv(4));
3924 else if (!strcmp(Cmd_Argv(1), "movex"))
3926 if (Cmd_Argc() != 3)
3928 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3931 origin[0] += atof(Cmd_Argv(2));
3933 else if (!strcmp(Cmd_Argv(1), "movey"))
3935 if (Cmd_Argc() != 3)
3937 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3940 origin[1] += atof(Cmd_Argv(2));
3942 else if (!strcmp(Cmd_Argv(1), "movez"))
3944 if (Cmd_Argc() != 3)
3946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3949 origin[2] += atof(Cmd_Argv(2));
3951 else if (!strcmp(Cmd_Argv(1), "angles"))
3953 if (Cmd_Argc() != 5)
3955 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3958 angles[0] = atof(Cmd_Argv(2));
3959 angles[1] = atof(Cmd_Argv(3));
3960 angles[2] = atof(Cmd_Argv(4));
3962 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3964 if (Cmd_Argc() != 3)
3966 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3969 angles[0] = atof(Cmd_Argv(2));
3971 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3973 if (Cmd_Argc() != 3)
3975 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3978 angles[1] = atof(Cmd_Argv(2));
3980 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3982 if (Cmd_Argc() != 3)
3984 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3987 angles[2] = atof(Cmd_Argv(2));
3989 else if (!strcmp(Cmd_Argv(1), "color"))
3991 if (Cmd_Argc() != 5)
3993 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3996 color[0] = atof(Cmd_Argv(2));
3997 color[1] = atof(Cmd_Argv(3));
3998 color[2] = atof(Cmd_Argv(4));
4000 else if (!strcmp(Cmd_Argv(1), "radius"))
4002 if (Cmd_Argc() != 3)
4004 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4007 radius = atof(Cmd_Argv(2));
4009 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4011 if (Cmd_Argc() == 3)
4013 double scale = atof(Cmd_Argv(2));
4020 if (Cmd_Argc() != 5)
4022 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4025 color[0] *= atof(Cmd_Argv(2));
4026 color[1] *= atof(Cmd_Argv(3));
4027 color[2] *= atof(Cmd_Argv(4));
4030 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4032 if (Cmd_Argc() != 3)
4034 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4037 radius *= atof(Cmd_Argv(2));
4039 else if (!strcmp(Cmd_Argv(1), "style"))
4041 if (Cmd_Argc() != 3)
4043 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4046 style = atoi(Cmd_Argv(2));
4048 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4052 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4055 if (Cmd_Argc() == 3)
4056 strcpy(cubemapname, Cmd_Argv(2));
4060 else if (!strcmp(Cmd_Argv(1), "shadows"))
4062 if (Cmd_Argc() != 3)
4064 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4067 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4069 else if (!strcmp(Cmd_Argv(1), "corona"))
4071 if (Cmd_Argc() != 3)
4073 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4076 corona = atof(Cmd_Argv(2));
4078 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4080 if (Cmd_Argc() != 3)
4082 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4085 coronasizescale = atof(Cmd_Argv(2));
4087 else if (!strcmp(Cmd_Argv(1), "ambient"))
4089 if (Cmd_Argc() != 3)
4091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4094 ambientscale = atof(Cmd_Argv(2));
4096 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4098 if (Cmd_Argc() != 3)
4100 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4103 diffusescale = atof(Cmd_Argv(2));
4105 else if (!strcmp(Cmd_Argv(1), "specular"))
4107 if (Cmd_Argc() != 3)
4109 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4112 specularscale = atof(Cmd_Argv(2));
4114 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4116 if (Cmd_Argc() != 3)
4118 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4121 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4123 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4125 if (Cmd_Argc() != 3)
4127 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4130 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4134 Con_Print("usage: r_editlights_edit [property] [value]\n");
4135 Con_Print("Selected light's properties:\n");
4136 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4137 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4138 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4139 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4140 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4141 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4142 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4143 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4144 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4145 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4146 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4147 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4148 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4149 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4152 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4153 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4156 void R_Shadow_EditLights_EditAll_f(void)
4160 if (!r_editlights.integer)
4162 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4166 for (light = r_shadow_worldlightchain;light;light = light->next)
4168 R_Shadow_SelectLight(light);
4169 R_Shadow_EditLights_Edit_f();
4173 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4175 int lightnumber, lightcount;
4179 if (!r_editlights.integer)
4185 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4186 if (light == r_shadow_selectedlight)
4187 lightnumber = lightcount;
4188 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;
4189 if (r_shadow_selectedlight == NULL)
4191 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4192 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;
4193 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;
4194 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;
4195 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4196 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4197 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4198 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;
4199 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4200 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4201 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4202 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4203 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4204 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;
4205 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;
4208 void R_Shadow_EditLights_ToggleShadow_f(void)
4210 if (!r_editlights.integer)
4212 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4215 if (!r_shadow_selectedlight)
4217 Con_Print("No selected light.\n");
4220 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);
4223 void R_Shadow_EditLights_ToggleCorona_f(void)
4225 if (!r_editlights.integer)
4227 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4230 if (!r_shadow_selectedlight)
4232 Con_Print("No selected light.\n");
4235 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);
4238 void R_Shadow_EditLights_Remove_f(void)
4240 if (!r_editlights.integer)
4242 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4245 if (!r_shadow_selectedlight)
4247 Con_Print("No selected light.\n");
4250 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4251 r_shadow_selectedlight = NULL;
4254 void R_Shadow_EditLights_Help_f(void)
4257 "Documentation on r_editlights system:\n"
4259 "r_editlights : enable/disable editing mode\n"
4260 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4261 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4262 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4263 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4264 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4266 "r_editlights_help : this help\n"
4267 "r_editlights_clear : remove all lights\n"
4268 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4269 "r_editlights_save : save to .rtlights file\n"
4270 "r_editlights_spawn : create a light with default settings\n"
4271 "r_editlights_edit command : edit selected light - more documentation below\n"
4272 "r_editlights_remove : remove selected light\n"
4273 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4274 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4275 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4277 "origin x y z : set light location\n"
4278 "originx x: set x component of light location\n"
4279 "originy y: set y component of light location\n"
4280 "originz z: set z component of light location\n"
4281 "move x y z : adjust light location\n"
4282 "movex x: adjust x component of light location\n"
4283 "movey y: adjust y component of light location\n"
4284 "movez z: adjust z component of light location\n"
4285 "angles x y z : set light angles\n"
4286 "anglesx x: set x component of light angles\n"
4287 "anglesy y: set y component of light angles\n"
4288 "anglesz z: set z component of light angles\n"
4289 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4290 "radius radius : set radius (size) of light\n"
4291 "colorscale grey : multiply color of light (1 does nothing)\n"
4292 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4293 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4294 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4295 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4296 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4297 "shadows 1/0 : turn on/off shadows\n"
4298 "corona n : set corona intensity\n"
4299 "coronasize n : set corona size (0-1)\n"
4300 "ambient n : set ambient intensity (0-1)\n"
4301 "diffuse n : set diffuse intensity (0-1)\n"
4302 "specular n : set specular intensity (0-1)\n"
4303 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4304 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4305 "<nothing> : print light properties to console\n"
4309 void R_Shadow_EditLights_CopyInfo_f(void)
4311 if (!r_editlights.integer)
4313 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4316 if (!r_shadow_selectedlight)
4318 Con_Print("No selected light.\n");
4321 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4322 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4323 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4324 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4325 if (r_shadow_selectedlight->cubemapname)
4326 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4328 r_shadow_bufferlight.cubemapname[0] = 0;
4329 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4330 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4331 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4332 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4333 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4334 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4335 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4338 void R_Shadow_EditLights_PasteInfo_f(void)
4340 if (!r_editlights.integer)
4342 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4345 if (!r_shadow_selectedlight)
4347 Con_Print("No selected light.\n");
4350 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);
4353 void R_Shadow_EditLights_Init(void)
4355 Cvar_RegisterVariable(&r_editlights);
4356 Cvar_RegisterVariable(&r_editlights_cursordistance);
4357 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4358 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4359 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4360 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4361 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4362 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4363 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)");
4364 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4365 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4366 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4367 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)");
4368 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4369 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4370 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4371 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4372 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4373 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4374 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)");