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_shadowstage_e
148 R_SHADOWSTAGE_STENCIL,
149 R_SHADOWSTAGE_STENCILTWOSIDE,
150 R_SHADOWSTAGE_LIGHT_VERTEX,
151 R_SHADOWSTAGE_LIGHT_DOT3,
152 R_SHADOWSTAGE_LIGHT_GLSL,
153 R_SHADOWSTAGE_VISIBLEVOLUMES,
154 R_SHADOWSTAGE_VISIBLELIGHTING,
158 r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
160 mempool_t *r_shadow_mempool;
162 int maxshadowelements;
176 int r_shadow_buffer_numleafpvsbytes;
177 qbyte *r_shadow_buffer_leafpvs;
178 int *r_shadow_buffer_leaflist;
180 int r_shadow_buffer_numsurfacepvsbytes;
181 qbyte *r_shadow_buffer_surfacepvs;
182 int *r_shadow_buffer_surfacelist;
184 rtexturepool_t *r_shadow_texturepool;
185 rtexture_t *r_shadow_attenuation2dtexture;
186 rtexture_t *r_shadow_attenuation3dtexture;
188 // lights are reloaded when this changes
189 char r_shadow_mapname[MAX_QPATH];
191 // used only for light filters (cubemaps)
192 rtexturepool_t *r_shadow_filters_texturepool;
194 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
195 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
196 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
197 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
198 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
199 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
200 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
201 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
202 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
203 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
204 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
205 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
206 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
207 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
208 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
209 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
210 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
211 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
212 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
213 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
214 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
215 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
216 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
217 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
218 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
219 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
220 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
221 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
222 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
223 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
224 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
225 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
226 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
227 cvar_t r_editlights = {0, "r_editlights", "0"};
228 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
229 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
230 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
231 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
232 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
233 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
234 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
236 float r_shadow_attenpower, r_shadow_attenscale;
238 rtlight_t *r_shadow_compilingrtlight;
239 dlight_t *r_shadow_worldlightchain;
240 dlight_t *r_shadow_selectedlight;
241 dlight_t r_shadow_bufferlight;
242 vec3_t r_editlights_cursorlocation;
244 rtexture_t *lighttextures[5];
246 extern int con_vislines;
248 typedef struct cubemapinfo_s
255 #define MAX_CUBEMAPS 256
256 static int numcubemaps;
257 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
259 #define SHADERPERMUTATION_SPECULAR (1<<0)
260 #define SHADERPERMUTATION_FOG (1<<1)
261 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
262 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
263 #define SHADERPERMUTATION_COUNT (1<<4)
265 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
267 void R_Shadow_UncompileWorldLights(void);
268 void R_Shadow_ClearWorldLights(void);
269 void R_Shadow_SaveWorldLights(void);
270 void R_Shadow_LoadWorldLights(void);
271 void R_Shadow_LoadLightsFile(void);
272 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
273 void R_Shadow_EditLights_Reload_f(void);
274 void R_Shadow_ValidateCvars(void);
275 static void R_Shadow_MakeTextures(void);
276 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
278 const char *builtinshader_light_vert =
279 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
280 "// written by Forest 'LordHavoc' Hale\n"
282 "uniform vec3 LightPosition;\n"
284 "varying vec2 TexCoord;\n"
285 "varying vec3 CubeVector;\n"
286 "varying vec3 LightVector;\n"
288 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
289 "uniform vec3 EyePosition;\n"
290 "varying vec3 EyeVector;\n"
293 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
297 " // copy the surface texcoord\n"
298 " TexCoord = gl_MultiTexCoord0.st;\n"
300 " // transform vertex position into light attenuation/cubemap space\n"
301 " // (-1 to +1 across the light box)\n"
302 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
304 " // transform unnormalized light direction into tangent space\n"
305 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
306 " // normalize it per pixel)\n"
307 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
308 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
309 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
310 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
312 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
313 " // transform unnormalized eye direction into tangent space\n"
314 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
315 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
316 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
317 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
320 " // transform vertex to camera space, using ftransform to match non-VS\n"
322 " gl_Position = ftransform();\n"
326 const char *builtinshader_light_frag =
327 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
328 "// written by Forest 'LordHavoc' Hale\n"
330 "uniform vec3 LightColor;\n"
332 "#ifdef USEOFFSETMAPPING\n"
333 "uniform float OffsetMapping_Scale;\n"
334 "uniform float OffsetMapping_Bias;\n"
336 "#ifdef USESPECULAR\n"
337 "uniform float SpecularPower;\n"
340 "uniform float FogRangeRecip;\n"
342 "uniform float AmbientScale;\n"
343 "uniform float DiffuseScale;\n"
344 "#ifdef USESPECULAR\n"
345 "uniform float SpecularScale;\n"
348 "uniform sampler2D Texture_Normal;\n"
349 "uniform sampler2D Texture_Color;\n"
350 "#ifdef USESPECULAR\n"
351 "uniform sampler2D Texture_Gloss;\n"
353 "#ifdef USECUBEFILTER\n"
354 "uniform samplerCube Texture_Cube;\n"
357 "uniform sampler2D Texture_FogMask;\n"
360 "varying vec2 TexCoord;\n"
361 "varying vec3 CubeVector;\n"
362 "varying vec3 LightVector;\n"
363 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
364 "varying vec3 EyeVector;\n"
371 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
372 " // center and sharp falloff at the edge, this is about the most efficient\n"
373 " // we can get away with as far as providing illumination.\n"
375 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
376 " // provide significant illumination, large = slow = pain.\n"
377 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
381 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
384 "#ifdef USEOFFSETMAPPING\n"
385 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
386 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
387 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
388 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
389 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
390 "#define TexCoord TexCoordOffset\n"
393 " // get the texels - with a blendmap we'd need to blend multiple here\n"
394 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
395 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
396 "#ifdef USESPECULAR\n"
397 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
400 " // calculate shading\n"
401 " vec3 diffusenormal = normalize(LightVector);\n"
402 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
403 "#ifdef USESPECULAR\n"
404 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
407 "#ifdef USECUBEFILTER\n"
408 " // apply light cubemap filter\n"
409 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
412 " // calculate fragment color\n"
413 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
417 void r_shadow_start(void)
420 // allocate vertex processing arrays
422 r_shadow_attenuation2dtexture = NULL;
423 r_shadow_attenuation3dtexture = NULL;
424 r_shadow_texturepool = NULL;
425 r_shadow_filters_texturepool = NULL;
426 R_Shadow_ValidateCvars();
427 R_Shadow_MakeTextures();
428 maxshadowelements = 0;
429 shadowelements = NULL;
437 shadowmarklist = NULL;
439 r_shadow_buffer_numleafpvsbytes = 0;
440 r_shadow_buffer_leafpvs = NULL;
441 r_shadow_buffer_leaflist = NULL;
442 r_shadow_buffer_numsurfacepvsbytes = 0;
443 r_shadow_buffer_surfacepvs = NULL;
444 r_shadow_buffer_surfacelist = NULL;
445 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
446 r_shadow_program_light[i] = 0;
447 if (gl_support_fragment_shader)
449 char *vertstring, *fragstring;
450 int vertstrings_count;
451 int fragstrings_count;
452 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
453 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
454 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
455 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
456 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
458 vertstrings_count = 0;
459 fragstrings_count = 0;
460 if (i & SHADERPERMUTATION_SPECULAR)
462 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
463 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
465 if (i & SHADERPERMUTATION_FOG)
467 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
468 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
470 if (i & SHADERPERMUTATION_CUBEFILTER)
472 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
473 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
475 if (i & SHADERPERMUTATION_OFFSETMAPPING)
477 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
478 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
480 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
481 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
482 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
483 if (!r_shadow_program_light[i])
485 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
488 qglUseProgramObjectARB(r_shadow_program_light[i]);
489 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
490 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
491 if (i & SHADERPERMUTATION_SPECULAR)
493 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
495 if (i & SHADERPERMUTATION_CUBEFILTER)
497 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
499 if (i & SHADERPERMUTATION_FOG)
501 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
504 qglUseProgramObjectARB(0);
506 Mem_Free(fragstring);
508 Mem_Free(vertstring);
512 void r_shadow_shutdown(void)
515 R_Shadow_UncompileWorldLights();
516 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
518 if (r_shadow_program_light[i])
520 GL_Backend_FreeProgram(r_shadow_program_light[i]);
521 r_shadow_program_light[i] = 0;
525 r_shadow_attenuation2dtexture = NULL;
526 r_shadow_attenuation3dtexture = NULL;
527 R_FreeTexturePool(&r_shadow_texturepool);
528 R_FreeTexturePool(&r_shadow_filters_texturepool);
529 maxshadowelements = 0;
531 Mem_Free(shadowelements);
532 shadowelements = NULL;
535 Mem_Free(vertexupdate);
538 Mem_Free(vertexremap);
544 Mem_Free(shadowmark);
547 Mem_Free(shadowmarklist);
548 shadowmarklist = NULL;
550 r_shadow_buffer_numleafpvsbytes = 0;
551 if (r_shadow_buffer_leafpvs)
552 Mem_Free(r_shadow_buffer_leafpvs);
553 r_shadow_buffer_leafpvs = NULL;
554 if (r_shadow_buffer_leaflist)
555 Mem_Free(r_shadow_buffer_leaflist);
556 r_shadow_buffer_leaflist = NULL;
557 r_shadow_buffer_numsurfacepvsbytes = 0;
558 if (r_shadow_buffer_surfacepvs)
559 Mem_Free(r_shadow_buffer_surfacepvs);
560 r_shadow_buffer_surfacepvs = NULL;
561 if (r_shadow_buffer_surfacelist)
562 Mem_Free(r_shadow_buffer_surfacelist);
563 r_shadow_buffer_surfacelist = NULL;
566 void r_shadow_newmap(void)
570 void R_Shadow_Help_f(void)
573 "Documentation on r_shadow system:\n"
575 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
576 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
577 "r_shadow_debuglight : render only this light number (-1 = all)\n"
578 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
579 "r_shadow_gloss2intensity : brightness of forced gloss\n"
580 "r_shadow_glossintensity : brightness of textured gloss\n"
581 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
582 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
583 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
584 "r_shadow_portallight : use portal visibility for static light precomputation\n"
585 "r_shadow_projectdistance : shadow volume projection distance\n"
586 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
587 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
588 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
589 "r_shadow_realtime_world : use high quality world lighting mode\n"
590 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
591 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
592 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
593 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
594 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
595 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
596 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
597 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
598 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
599 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
600 "r_shadow_scissor : use scissor optimization\n"
601 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
602 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
603 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
604 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
605 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
606 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
608 "r_shadow_help : this help\n"
612 void R_Shadow_Init(void)
614 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
615 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
616 Cvar_RegisterVariable(&r_shadow_debuglight);
617 Cvar_RegisterVariable(&r_shadow_gloss);
618 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
619 Cvar_RegisterVariable(&r_shadow_glossintensity);
620 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
621 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
622 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
623 Cvar_RegisterVariable(&r_shadow_portallight);
624 Cvar_RegisterVariable(&r_shadow_projectdistance);
625 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
626 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
627 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
628 Cvar_RegisterVariable(&r_shadow_realtime_world);
629 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
630 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
631 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
632 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
633 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
634 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
635 Cvar_RegisterVariable(&r_shadow_scissor);
636 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
637 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
638 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
639 Cvar_RegisterVariable(&r_shadow_texture3d);
640 Cvar_RegisterVariable(&r_shadow_visiblelighting);
641 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
642 Cvar_RegisterVariable(&r_shadow_glsl);
643 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
644 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
645 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
646 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
647 if (gamemode == GAME_TENEBRAE)
649 Cvar_SetValue("r_shadow_gloss", 2);
650 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
652 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
653 R_Shadow_EditLights_Init();
654 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
655 r_shadow_worldlightchain = NULL;
656 maxshadowelements = 0;
657 shadowelements = NULL;
665 shadowmarklist = NULL;
667 r_shadow_buffer_numleafpvsbytes = 0;
668 r_shadow_buffer_leafpvs = NULL;
669 r_shadow_buffer_leaflist = NULL;
670 r_shadow_buffer_numsurfacepvsbytes = 0;
671 r_shadow_buffer_surfacepvs = NULL;
672 r_shadow_buffer_surfacelist = NULL;
673 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
676 static matrix4x4_t matrix_attenuationxyz =
679 {0.5, 0.0, 0.0, 0.5},
680 {0.0, 0.5, 0.0, 0.5},
681 {0.0, 0.0, 0.5, 0.5},
686 static matrix4x4_t matrix_attenuationz =
689 {0.0, 0.0, 0.5, 0.5},
690 {0.0, 0.0, 0.0, 0.5},
691 {0.0, 0.0, 0.0, 0.5},
696 int *R_Shadow_ResizeShadowElements(int numtris)
698 // make sure shadowelements is big enough for this volume
699 if (maxshadowelements < numtris * 24)
701 maxshadowelements = numtris * 24;
703 Mem_Free(shadowelements);
704 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
706 return shadowelements;
709 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
711 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
712 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
713 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
715 if (r_shadow_buffer_leafpvs)
716 Mem_Free(r_shadow_buffer_leafpvs);
717 if (r_shadow_buffer_leaflist)
718 Mem_Free(r_shadow_buffer_leaflist);
719 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
720 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
721 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
723 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
725 if (r_shadow_buffer_surfacepvs)
726 Mem_Free(r_shadow_buffer_surfacepvs);
727 if (r_shadow_buffer_surfacelist)
728 Mem_Free(r_shadow_buffer_surfacelist);
729 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
730 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
731 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
735 void R_Shadow_PrepareShadowMark(int numtris)
737 // make sure shadowmark is big enough for this volume
738 if (maxshadowmark < numtris)
740 maxshadowmark = numtris;
742 Mem_Free(shadowmark);
744 Mem_Free(shadowmarklist);
745 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
746 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
750 // if shadowmarkcount wrapped we clear the array and adjust accordingly
751 if (shadowmarkcount == 0)
754 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
759 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)
762 int outtriangles = 0, outvertices = 0;
766 if (maxvertexupdate < innumvertices)
768 maxvertexupdate = innumvertices;
770 Mem_Free(vertexupdate);
772 Mem_Free(vertexremap);
773 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
774 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
778 if (vertexupdatenum == 0)
781 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
782 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
785 for (i = 0;i < numshadowmarktris;i++)
786 shadowmark[shadowmarktris[i]] = shadowmarkcount;
788 for (i = 0;i < numshadowmarktris;i++)
790 element = inelement3i + shadowmarktris[i] * 3;
791 // make sure the vertices are created
792 for (j = 0;j < 3;j++)
794 if (vertexupdate[element[j]] != vertexupdatenum)
796 float ratio, direction[3];
797 vertexupdate[element[j]] = vertexupdatenum;
798 vertexremap[element[j]] = outvertices;
799 vertex = invertex3f + element[j] * 3;
800 // project one copy of the vertex to the sphere radius of the light
801 // (FIXME: would projecting it to the light box be better?)
802 VectorSubtract(vertex, projectorigin, direction);
803 ratio = projectdistance / VectorLength(direction);
804 VectorCopy(vertex, outvertex3f);
805 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
812 for (i = 0;i < numshadowmarktris;i++)
814 int remappedelement[3];
816 const int *neighbortriangle;
818 markindex = shadowmarktris[i] * 3;
819 element = inelement3i + markindex;
820 neighbortriangle = inneighbor3i + markindex;
821 // output the front and back triangles
822 outelement3i[0] = vertexremap[element[0]];
823 outelement3i[1] = vertexremap[element[1]];
824 outelement3i[2] = vertexremap[element[2]];
825 outelement3i[3] = vertexremap[element[2]] + 1;
826 outelement3i[4] = vertexremap[element[1]] + 1;
827 outelement3i[5] = vertexremap[element[0]] + 1;
831 // output the sides (facing outward from this triangle)
832 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
834 remappedelement[0] = vertexremap[element[0]];
835 remappedelement[1] = vertexremap[element[1]];
836 outelement3i[0] = remappedelement[1];
837 outelement3i[1] = remappedelement[0];
838 outelement3i[2] = remappedelement[0] + 1;
839 outelement3i[3] = remappedelement[1];
840 outelement3i[4] = remappedelement[0] + 1;
841 outelement3i[5] = remappedelement[1] + 1;
846 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
848 remappedelement[1] = vertexremap[element[1]];
849 remappedelement[2] = vertexremap[element[2]];
850 outelement3i[0] = remappedelement[2];
851 outelement3i[1] = remappedelement[1];
852 outelement3i[2] = remappedelement[1] + 1;
853 outelement3i[3] = remappedelement[2];
854 outelement3i[4] = remappedelement[1] + 1;
855 outelement3i[5] = remappedelement[2] + 1;
860 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
862 remappedelement[0] = vertexremap[element[0]];
863 remappedelement[2] = vertexremap[element[2]];
864 outelement3i[0] = remappedelement[0];
865 outelement3i[1] = remappedelement[2];
866 outelement3i[2] = remappedelement[2] + 1;
867 outelement3i[3] = remappedelement[0];
868 outelement3i[4] = remappedelement[2] + 1;
869 outelement3i[5] = remappedelement[0] + 1;
876 *outnumvertices = outvertices;
880 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)
883 if (projectdistance < 0.1)
885 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
888 if (!numverts || !nummarktris)
890 // make sure shadowelements is big enough for this volume
891 if (maxshadowelements < nummarktris * 24)
892 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
893 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
894 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
897 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)
902 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
904 tend = firsttriangle + numtris;
905 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
906 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
907 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
909 // surface box entirely inside light box, no box cull
910 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
911 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
912 shadowmarklist[numshadowmark++] = t;
916 // surface box not entirely inside light box, cull each triangle
917 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
919 v[0] = invertex3f + e[0] * 3;
920 v[1] = invertex3f + e[1] * 3;
921 v[2] = invertex3f + e[2] * 3;
922 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
923 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
924 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
925 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
926 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
927 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
928 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
929 shadowmarklist[numshadowmark++] = t;
934 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
937 if (r_shadow_compilingrtlight)
939 // if we're compiling an rtlight, capture the mesh
940 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
943 memset(&m, 0, sizeof(m));
944 m.pointer_vertex = vertex3f;
946 GL_LockArrays(0, numvertices);
947 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
949 // decrement stencil if backface is behind depthbuffer
950 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
951 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
952 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
954 c_rt_shadowtris += numtriangles;
955 // increment stencil if frontface is behind depthbuffer
956 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
957 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
959 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
961 c_rt_shadowtris += numtriangles;
965 static void R_Shadow_MakeTextures(void)
968 float v[3], intensity;
970 R_FreeTexturePool(&r_shadow_texturepool);
971 r_shadow_texturepool = R_AllocTexturePool();
972 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
973 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
974 #define ATTEN2DSIZE 64
975 #define ATTEN3DSIZE 32
976 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
977 for (y = 0;y < ATTEN2DSIZE;y++)
979 for (x = 0;x < ATTEN2DSIZE;x++)
981 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
982 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
984 intensity = 1.0f - sqrt(DotProduct(v, v));
986 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
987 d = bound(0, intensity, 255);
988 data[(y*ATTEN2DSIZE+x)*4+0] = d;
989 data[(y*ATTEN2DSIZE+x)*4+1] = d;
990 data[(y*ATTEN2DSIZE+x)*4+2] = d;
991 data[(y*ATTEN2DSIZE+x)*4+3] = d;
994 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
995 if (r_shadow_texture3d.integer)
997 for (z = 0;z < ATTEN3DSIZE;z++)
999 for (y = 0;y < ATTEN3DSIZE;y++)
1001 for (x = 0;x < ATTEN3DSIZE;x++)
1003 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1004 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1005 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1006 intensity = 1.0f - sqrt(DotProduct(v, v));
1008 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1009 d = bound(0, intensity, 255);
1010 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1011 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1012 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1013 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1017 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1022 void R_Shadow_ValidateCvars(void)
1024 if (r_shadow_texture3d.integer && !gl_texture3d)
1025 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1026 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1027 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1030 // light currently being rendered
1031 static rtlight_t *r_shadow_rtlight;
1032 // light filter cubemap being used by the light
1033 static rtexture_t *r_shadow_lightcubemap;
1035 // this is the location of the eye in entity space
1036 static vec3_t r_shadow_entityeyeorigin;
1037 // this is the location of the light in entity space
1038 static vec3_t r_shadow_entitylightorigin;
1039 // this transforms entity coordinates to light filter cubemap coordinates
1040 // (also often used for other purposes)
1041 static matrix4x4_t r_shadow_entitytolight;
1042 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1043 // of attenuation texturing in full 3D (Z result often ignored)
1044 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1045 // this transforms only the Z to S, and T is always 0.5
1046 static matrix4x4_t r_shadow_entitytoattenuationz;
1047 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1048 static vec3_t r_shadow_entitylightcolor;
1050 static int r_shadow_lightpermutation;
1051 static int r_shadow_lightprog;
1053 void R_Shadow_Stage_Begin(void)
1057 R_Shadow_ValidateCvars();
1059 if (!r_shadow_attenuation2dtexture
1060 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1061 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1062 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1063 R_Shadow_MakeTextures();
1065 memset(&m, 0, sizeof(m));
1066 GL_BlendFunc(GL_ONE, GL_ZERO);
1067 GL_DepthMask(false);
1070 GL_Color(0, 0, 0, 1);
1071 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1072 qglEnable(GL_CULL_FACE);
1073 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1074 r_shadowstage = R_SHADOWSTAGE_NONE;
1077 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1079 r_shadow_rtlight = rtlight;
1082 void R_Shadow_Stage_Reset(void)
1085 if (gl_support_stenciltwoside)
1086 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1087 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1089 qglUseProgramObjectARB(0);
1090 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1091 qglBegin(GL_TRIANGLES);
1095 memset(&m, 0, sizeof(m));
1099 void R_Shadow_Stage_StencilShadowVolumes(void)
1101 R_Shadow_Stage_Reset();
1102 GL_Color(1, 1, 1, 1);
1103 GL_ColorMask(0, 0, 0, 0);
1104 GL_BlendFunc(GL_ONE, GL_ZERO);
1105 GL_DepthMask(false);
1107 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1108 //if (r_shadow_shadow_polygonoffset.value != 0)
1110 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1111 // qglEnable(GL_POLYGON_OFFSET_FILL);
1114 // qglDisable(GL_POLYGON_OFFSET_FILL);
1115 qglDepthFunc(GL_LESS);
1116 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1117 qglEnable(GL_STENCIL_TEST);
1118 qglStencilFunc(GL_ALWAYS, 128, ~0);
1119 if (gl_ext_stenciltwoside.integer)
1121 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1122 qglDisable(GL_CULL_FACE);
1123 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1124 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1126 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1127 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1129 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1133 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1134 qglEnable(GL_CULL_FACE);
1136 // this is changed by every shadow render so its value here is unimportant
1137 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1139 GL_Clear(GL_STENCIL_BUFFER_BIT);
1143 void R_Shadow_Stage_Lighting(int stenciltest)
1146 R_Shadow_Stage_Reset();
1147 GL_BlendFunc(GL_ONE, GL_ONE);
1148 GL_DepthMask(false);
1150 qglPolygonOffset(0, 0);
1151 //qglDisable(GL_POLYGON_OFFSET_FILL);
1152 GL_Color(1, 1, 1, 1);
1153 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1154 qglDepthFunc(GL_EQUAL);
1155 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1156 qglEnable(GL_CULL_FACE);
1157 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1158 qglEnable(GL_STENCIL_TEST);
1160 qglDisable(GL_STENCIL_TEST);
1162 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1163 // only draw light where this geometry was already rendered AND the
1164 // stencil is 128 (values other than this mean shadow)
1165 qglStencilFunc(GL_EQUAL, 128, ~0);
1166 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1168 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1169 memset(&m, 0, sizeof(m));
1170 m.pointer_vertex = varray_vertex3f;
1171 m.pointer_texcoord[0] = varray_texcoord2f[0];
1172 m.pointer_texcoord3f[1] = varray_svector3f;
1173 m.pointer_texcoord3f[2] = varray_tvector3f;
1174 m.pointer_texcoord3f[3] = varray_normal3f;
1175 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1176 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1177 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1178 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1179 // TODO: support fog (after renderer is converted to texture fog)
1180 m.tex[4] = R_GetTexture(r_texture_white); // fog
1181 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1183 GL_BlendFunc(GL_ONE, GL_ONE);
1184 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1186 r_shadow_lightpermutation = 0;
1187 // only add a feature to the permutation if that permutation exists
1188 // (otherwise it might end up not using a shader at all, which looks
1189 // worse than using less features)
1190 if (r_shadow_rtlight->specularscale && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1191 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1192 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1193 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1194 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1195 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1196 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1197 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1198 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1199 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1200 // TODO: support fog (after renderer is converted to texture fog)
1201 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1203 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1205 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1206 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1207 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1209 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1210 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1212 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1213 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1214 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1216 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1218 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1220 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1221 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1224 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1225 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1227 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1230 void R_Shadow_Stage_VisibleShadowVolumes(void)
1232 R_Shadow_Stage_Reset();
1233 GL_BlendFunc(GL_ONE, GL_ONE);
1234 GL_DepthMask(false);
1235 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1236 qglPolygonOffset(0, 0);
1237 GL_Color(0.0, 0.0125, 0.1, 1);
1238 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1239 qglDepthFunc(GL_GEQUAL);
1240 qglCullFace(GL_FRONT); // this culls back
1241 qglDisable(GL_CULL_FACE);
1242 qglDisable(GL_STENCIL_TEST);
1243 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1246 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1248 R_Shadow_Stage_Reset();
1249 GL_BlendFunc(GL_ONE, GL_ONE);
1250 GL_DepthMask(false);
1251 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1252 qglPolygonOffset(0, 0);
1253 GL_Color(0.1, 0.0125, 0, 1);
1254 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1255 qglDepthFunc(GL_EQUAL);
1256 qglCullFace(GL_FRONT); // this culls back
1257 qglEnable(GL_CULL_FACE);
1259 qglEnable(GL_STENCIL_TEST);
1261 qglDisable(GL_STENCIL_TEST);
1262 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1265 void R_Shadow_Stage_End(void)
1267 R_Shadow_Stage_Reset();
1268 R_Shadow_Stage_ActiveLight(NULL);
1269 GL_BlendFunc(GL_ONE, GL_ZERO);
1272 qglPolygonOffset(0, 0);
1273 //qglDisable(GL_POLYGON_OFFSET_FILL);
1274 GL_Color(1, 1, 1, 1);
1275 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1276 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1277 qglDepthFunc(GL_LEQUAL);
1278 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1279 qglDisable(GL_STENCIL_TEST);
1280 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1281 if (gl_support_stenciltwoside)
1282 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1284 qglStencilFunc(GL_ALWAYS, 128, ~0);
1285 r_shadowstage = R_SHADOWSTAGE_NONE;
1288 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1290 int i, ix1, iy1, ix2, iy2;
1291 float x1, y1, x2, y2;
1294 mplane_t planes[11];
1295 float vertex3f[256*3];
1297 // if view is inside the light box, just say yes it's visible
1298 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1300 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1304 // create a temporary brush describing the area the light can affect in worldspace
1305 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1306 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1307 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1308 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1309 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1310 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1311 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1312 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1313 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1314 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1315 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1317 // turn the brush into a mesh
1318 memset(&mesh, 0, sizeof(rmesh_t));
1319 mesh.maxvertices = 256;
1320 mesh.vertex3f = vertex3f;
1321 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1322 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1324 // if that mesh is empty, the light is not visible at all
1325 if (!mesh.numvertices)
1328 if (!r_shadow_scissor.integer)
1331 // if that mesh is not empty, check what area of the screen it covers
1332 x1 = y1 = x2 = y2 = 0;
1334 for (i = 0;i < mesh.numvertices;i++)
1336 VectorCopy(mesh.vertex3f + i * 3, v);
1337 GL_TransformToScreen(v, v2);
1338 //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]);
1341 if (x1 > v2[0]) x1 = v2[0];
1342 if (x2 < v2[0]) x2 = v2[0];
1343 if (y1 > v2[1]) y1 = v2[1];
1344 if (y2 < v2[1]) y2 = v2[1];
1353 // now convert the scissor rectangle to integer screen coordinates
1358 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1360 // clamp it to the screen
1361 if (ix1 < r_view_x) ix1 = r_view_x;
1362 if (iy1 < r_view_y) iy1 = r_view_y;
1363 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1364 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1366 // if it is inside out, it's not visible
1367 if (ix2 <= ix1 || iy2 <= iy1)
1370 // the light area is visible, set up the scissor rectangle
1371 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1372 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1373 //qglEnable(GL_SCISSOR_TEST);
1378 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1380 float *color4f = varray_color4f;
1381 float dist, dot, intensity, v[3], n[3];
1382 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1384 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1385 if ((dist = DotProduct(v, v)) < 1)
1387 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1388 if ((dot = DotProduct(n, v)) > 0)
1391 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1392 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1393 VectorScale(lightcolor, intensity, color4f);
1398 VectorClear(color4f);
1404 VectorClear(color4f);
1410 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1412 float *color4f = varray_color4f;
1413 float dist, dot, intensity, v[3], n[3];
1414 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1416 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1417 if ((dist = fabs(v[2])) < 1)
1419 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1420 if ((dot = DotProduct(n, v)) > 0)
1422 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1423 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1424 VectorScale(lightcolor, intensity, color4f);
1429 VectorClear(color4f);
1435 VectorClear(color4f);
1441 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1443 float *color4f = varray_color4f;
1444 float dot, intensity, v[3], n[3];
1445 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1447 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1448 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1449 if ((dot = DotProduct(n, v)) > 0)
1451 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1452 VectorScale(lightcolor, intensity, color4f);
1457 VectorClear(color4f);
1463 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1465 float *color4f = varray_color4f;
1466 float dist, intensity, v[3];
1467 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1469 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1470 if ((dist = DotProduct(v, v)) < 1)
1473 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1474 VectorScale(lightcolor, intensity, color4f);
1479 VectorClear(color4f);
1485 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1487 float *color4f = varray_color4f;
1488 float dist, intensity, v[3];
1489 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1491 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1492 if ((dist = fabs(v[2])) < 1)
1494 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1495 VectorScale(lightcolor, intensity, color4f);
1500 VectorClear(color4f);
1506 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1507 #define USETEXMATRIX
1509 #ifndef USETEXMATRIX
1510 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1511 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1512 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1516 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1517 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1518 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1525 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1529 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1530 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1538 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)
1542 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1544 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1545 // the cubemap normalizes this for us
1546 out3f[0] = DotProduct(svector3f, lightdir);
1547 out3f[1] = DotProduct(tvector3f, lightdir);
1548 out3f[2] = DotProduct(normal3f, lightdir);
1552 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)
1555 float lightdir[3], eyedir[3], halfdir[3];
1556 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1558 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1559 VectorNormalizeFast(lightdir);
1560 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1561 VectorNormalizeFast(eyedir);
1562 VectorAdd(lightdir, eyedir, halfdir);
1563 // the cubemap normalizes this for us
1564 out3f[0] = DotProduct(svector3f, halfdir);
1565 out3f[1] = DotProduct(tvector3f, halfdir);
1566 out3f[2] = DotProduct(normal3f, halfdir);
1570 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture)
1573 float color[3], color2[3], colorscale, specularscale;
1575 // FIXME: support EF_NODEPTHTEST
1577 basetexture = r_texture_white;
1579 bumptexture = r_texture_blanknormalmap;
1581 lightcolorpants = vec3_origin;
1583 lightcolorshirt = vec3_origin;
1584 if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1585 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
1586 else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1588 glosstexture = r_texture_white;
1589 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
1593 glosstexture = r_texture_black;
1596 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1598 if (r_shadowstage == R_SHADOWSTAGE_VISIBLELIGHTING)
1601 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1602 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1603 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1605 // TODO: add direct pants/shirt rendering
1606 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1607 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1608 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1609 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1610 if (r_shadow_rtlight->ambientscale)
1612 colorscale = r_shadow_rtlight->ambientscale;
1613 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1616 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1619 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1622 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1627 VectorScale(lightcolorbase, colorscale, color2);
1628 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1631 if (r_shadow_rtlight->diffusescale)
1633 colorscale = r_shadow_rtlight->diffusescale;
1634 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1636 // 3/2 3D combine path (Geforce3, Radeon 8500)
1639 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1641 // 1/2/2 3D combine path (original Radeon)
1644 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1646 // 2/2 3D combine path (original Radeon)
1649 else if (r_textureunits.integer >= 4)
1651 // 4/2 2D combine path (Geforce3, Radeon 8500)
1656 // 2/2/2 2D combine path (any dot3 card)
1659 VectorScale(lightcolorbase, colorscale, color2);
1660 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1663 if (specularscale && glosstexture != r_texture_black)
1665 //if (gl_support_blendsquare)
1667 colorscale = specularscale;
1668 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1670 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1674 VectorScale(lightcolorbase, colorscale, color2);
1675 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1682 // TODO: add direct pants/shirt rendering
1683 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1684 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1685 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1686 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1687 if (r_shadow_rtlight->ambientscale)
1689 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
1690 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1693 if (r_shadow_rtlight->diffusescale)
1695 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
1696 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1702 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1703 memset(&m, 0, sizeof(m));
1704 m.pointer_vertex = vertex3f;
1706 GL_LockArrays(firstvertex, numvertices);
1707 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1708 GL_LockArrays(0, 0);
1712 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1714 // GLSL shader path (GFFX5200, Radeon 9500)
1715 R_Mesh_VertexPointer(vertex3f);
1716 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1717 R_Mesh_TexCoordPointer(1, 3, svector3f);
1718 R_Mesh_TexCoordPointer(2, 3, tvector3f);
1719 R_Mesh_TexCoordPointer(3, 3, normal3f);
1720 R_Mesh_TexBind(0, R_GetTexture(bumptexture));
1721 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1722 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1723 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1725 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1727 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1728 GL_LockArrays(firstvertex, numvertices);
1729 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1731 c_rt_lighttris += numtriangles;
1732 // TODO: add direct pants/shirt rendering
1733 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1735 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1736 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1737 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1739 c_rt_lighttris += numtriangles;
1741 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1743 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1744 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1745 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1747 c_rt_lighttris += numtriangles;
1749 GL_LockArrays(0, 0);
1751 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
1753 // TODO: add direct pants/shirt rendering
1754 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1755 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1756 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1757 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1758 if (r_shadow_rtlight->ambientscale)
1761 colorscale = r_shadow_rtlight->ambientscale;
1762 // colorscale accounts for how much we multiply the brightness
1765 // mult is how many times the final pass of the lighting will be
1766 // performed to get more brightness than otherwise possible.
1768 // Limit mult to 64 for sanity sake.
1769 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1771 // 3 3D combine path (Geforce3, Radeon 8500)
1772 memset(&m, 0, sizeof(m));
1773 m.pointer_vertex = vertex3f;
1774 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1776 m.pointer_texcoord3f[0] = vertex3f;
1777 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1779 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1780 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1782 m.tex[1] = R_GetTexture(basetexture);
1783 m.pointer_texcoord[1] = texcoord2f;
1784 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1786 m.pointer_texcoord3f[2] = vertex3f;
1787 m.texmatrix[2] = r_shadow_entitytolight;
1789 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1790 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1792 GL_BlendFunc(GL_ONE, GL_ONE);
1794 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1796 // 2 3D combine path (Geforce3, original Radeon)
1797 memset(&m, 0, sizeof(m));
1798 m.pointer_vertex = vertex3f;
1799 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1801 m.pointer_texcoord3f[0] = vertex3f;
1802 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1804 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1805 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1807 m.tex[1] = R_GetTexture(basetexture);
1808 m.pointer_texcoord[1] = texcoord2f;
1809 GL_BlendFunc(GL_ONE, GL_ONE);
1811 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1813 // 4 2D combine path (Geforce3, Radeon 8500)
1814 memset(&m, 0, sizeof(m));
1815 m.pointer_vertex = vertex3f;
1816 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1818 m.pointer_texcoord3f[0] = vertex3f;
1819 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1821 m.pointer_texcoord[0] = varray_texcoord2f[0];
1822 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1824 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1826 m.pointer_texcoord3f[1] = vertex3f;
1827 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1829 m.pointer_texcoord[1] = varray_texcoord2f[1];
1830 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1832 m.tex[2] = R_GetTexture(basetexture);
1833 m.pointer_texcoord[2] = texcoord2f;
1834 if (r_shadow_lightcubemap != r_texture_whitecube)
1836 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1838 m.pointer_texcoord3f[3] = vertex3f;
1839 m.texmatrix[3] = r_shadow_entitytolight;
1841 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1842 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1845 GL_BlendFunc(GL_ONE, GL_ONE);
1847 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1849 // 3 2D combine path (Geforce3, original Radeon)
1850 memset(&m, 0, sizeof(m));
1851 m.pointer_vertex = vertex3f;
1852 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1854 m.pointer_texcoord3f[0] = vertex3f;
1855 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1857 m.pointer_texcoord[0] = varray_texcoord2f[0];
1858 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1860 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1862 m.pointer_texcoord3f[1] = vertex3f;
1863 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1865 m.pointer_texcoord[1] = varray_texcoord2f[1];
1866 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1868 m.tex[2] = R_GetTexture(basetexture);
1869 m.pointer_texcoord[2] = texcoord2f;
1870 GL_BlendFunc(GL_ONE, GL_ONE);
1874 // 2/2/2 2D combine path (any dot3 card)
1875 memset(&m, 0, sizeof(m));
1876 m.pointer_vertex = vertex3f;
1877 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1879 m.pointer_texcoord3f[0] = vertex3f;
1880 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1882 m.pointer_texcoord[0] = varray_texcoord2f[0];
1883 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1885 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1887 m.pointer_texcoord3f[1] = vertex3f;
1888 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1890 m.pointer_texcoord[1] = varray_texcoord2f[1];
1891 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1894 GL_ColorMask(0,0,0,1);
1895 GL_BlendFunc(GL_ONE, GL_ZERO);
1896 GL_LockArrays(firstvertex, numvertices);
1897 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1898 GL_LockArrays(0, 0);
1900 c_rt_lighttris += numtriangles;
1902 memset(&m, 0, sizeof(m));
1903 m.pointer_vertex = vertex3f;
1904 m.tex[0] = R_GetTexture(basetexture);
1905 m.pointer_texcoord[0] = texcoord2f;
1906 if (r_shadow_lightcubemap != r_texture_whitecube)
1908 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1910 m.pointer_texcoord3f[1] = vertex3f;
1911 m.texmatrix[1] = r_shadow_entitytolight;
1913 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1914 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1917 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1919 // this final code is shared
1921 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1922 VectorScale(lightcolorbase, colorscale, color2);
1923 GL_LockArrays(firstvertex, numvertices);
1924 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1926 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1927 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1929 c_rt_lighttris += numtriangles;
1931 GL_LockArrays(0, 0);
1933 if (r_shadow_rtlight->diffusescale)
1936 colorscale = r_shadow_rtlight->diffusescale;
1937 // colorscale accounts for how much we multiply the brightness
1940 // mult is how many times the final pass of the lighting will be
1941 // performed to get more brightness than otherwise possible.
1943 // Limit mult to 64 for sanity sake.
1944 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1946 // 3/2 3D combine path (Geforce3, Radeon 8500)
1947 memset(&m, 0, sizeof(m));
1948 m.pointer_vertex = vertex3f;
1949 m.tex[0] = R_GetTexture(bumptexture);
1950 m.texcombinergb[0] = GL_REPLACE;
1951 m.pointer_texcoord[0] = texcoord2f;
1952 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1953 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1954 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1955 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
1956 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1958 m.pointer_texcoord3f[2] = vertex3f;
1959 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1961 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1962 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1965 GL_ColorMask(0,0,0,1);
1966 GL_BlendFunc(GL_ONE, GL_ZERO);
1967 GL_LockArrays(firstvertex, numvertices);
1968 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1969 GL_LockArrays(0, 0);
1971 c_rt_lighttris += numtriangles;
1973 memset(&m, 0, sizeof(m));
1974 m.pointer_vertex = vertex3f;
1975 m.tex[0] = R_GetTexture(basetexture);
1976 m.pointer_texcoord[0] = texcoord2f;
1977 if (r_shadow_lightcubemap != r_texture_whitecube)
1979 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1981 m.pointer_texcoord3f[1] = vertex3f;
1982 m.texmatrix[1] = r_shadow_entitytolight;
1984 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1985 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1988 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1990 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1992 // 1/2/2 3D combine path (original Radeon)
1993 memset(&m, 0, sizeof(m));
1994 m.pointer_vertex = vertex3f;
1995 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1997 m.pointer_texcoord3f[0] = vertex3f;
1998 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2000 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2001 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2004 GL_ColorMask(0,0,0,1);
2005 GL_BlendFunc(GL_ONE, GL_ZERO);
2006 GL_LockArrays(firstvertex, numvertices);
2007 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2008 GL_LockArrays(0, 0);
2010 c_rt_lighttris += numtriangles;
2012 memset(&m, 0, sizeof(m));
2013 m.pointer_vertex = vertex3f;
2014 m.tex[0] = R_GetTexture(bumptexture);
2015 m.texcombinergb[0] = GL_REPLACE;
2016 m.pointer_texcoord[0] = texcoord2f;
2017 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2018 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2019 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2020 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2022 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2023 GL_LockArrays(firstvertex, numvertices);
2024 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2025 GL_LockArrays(0, 0);
2027 c_rt_lighttris += numtriangles;
2029 memset(&m, 0, sizeof(m));
2030 m.pointer_vertex = vertex3f;
2031 m.tex[0] = R_GetTexture(basetexture);
2032 m.pointer_texcoord[0] = texcoord2f;
2033 if (r_shadow_lightcubemap != r_texture_whitecube)
2035 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2037 m.pointer_texcoord3f[1] = vertex3f;
2038 m.texmatrix[1] = r_shadow_entitytolight;
2040 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2041 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2044 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2046 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2048 // 2/2 3D combine path (original Radeon)
2049 memset(&m, 0, sizeof(m));
2050 m.pointer_vertex = vertex3f;
2051 m.tex[0] = R_GetTexture(bumptexture);
2052 m.texcombinergb[0] = GL_REPLACE;
2053 m.pointer_texcoord[0] = texcoord2f;
2054 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2055 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2056 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2057 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2059 GL_ColorMask(0,0,0,1);
2060 GL_BlendFunc(GL_ONE, GL_ZERO);
2061 GL_LockArrays(firstvertex, numvertices);
2062 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2063 GL_LockArrays(0, 0);
2065 c_rt_lighttris += numtriangles;
2067 memset(&m, 0, sizeof(m));
2068 m.pointer_vertex = vertex3f;
2069 m.tex[0] = R_GetTexture(basetexture);
2070 m.pointer_texcoord[0] = texcoord2f;
2071 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2073 m.pointer_texcoord3f[1] = vertex3f;
2074 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2076 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2077 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2079 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2081 else if (r_textureunits.integer >= 4)
2083 // 4/2 2D combine path (Geforce3, Radeon 8500)
2084 memset(&m, 0, sizeof(m));
2085 m.pointer_vertex = vertex3f;
2086 m.tex[0] = R_GetTexture(bumptexture);
2087 m.texcombinergb[0] = GL_REPLACE;
2088 m.pointer_texcoord[0] = texcoord2f;
2089 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2090 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2091 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2092 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2093 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2095 m.pointer_texcoord3f[2] = vertex3f;
2096 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2098 m.pointer_texcoord[2] = varray_texcoord2f[2];
2099 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2101 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2103 m.pointer_texcoord3f[3] = vertex3f;
2104 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2106 m.pointer_texcoord[3] = varray_texcoord2f[3];
2107 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2110 GL_ColorMask(0,0,0,1);
2111 GL_BlendFunc(GL_ONE, GL_ZERO);
2112 GL_LockArrays(firstvertex, numvertices);
2113 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2114 GL_LockArrays(0, 0);
2116 c_rt_lighttris += numtriangles;
2118 memset(&m, 0, sizeof(m));
2119 m.pointer_vertex = vertex3f;
2120 m.tex[0] = R_GetTexture(basetexture);
2121 m.pointer_texcoord[0] = texcoord2f;
2122 if (r_shadow_lightcubemap != r_texture_whitecube)
2124 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2126 m.pointer_texcoord3f[1] = vertex3f;
2127 m.texmatrix[1] = r_shadow_entitytolight;
2129 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2130 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2133 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2137 // 2/2/2 2D combine path (any dot3 card)
2138 memset(&m, 0, sizeof(m));
2139 m.pointer_vertex = vertex3f;
2140 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2142 m.pointer_texcoord3f[0] = vertex3f;
2143 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2145 m.pointer_texcoord[0] = varray_texcoord2f[0];
2146 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2148 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2150 m.pointer_texcoord3f[1] = vertex3f;
2151 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2153 m.pointer_texcoord[1] = varray_texcoord2f[1];
2154 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2157 GL_ColorMask(0,0,0,1);
2158 GL_BlendFunc(GL_ONE, GL_ZERO);
2159 GL_LockArrays(firstvertex, numvertices);
2160 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2161 GL_LockArrays(0, 0);
2163 c_rt_lighttris += numtriangles;
2165 memset(&m, 0, sizeof(m));
2166 m.pointer_vertex = vertex3f;
2167 m.tex[0] = R_GetTexture(bumptexture);
2168 m.texcombinergb[0] = GL_REPLACE;
2169 m.pointer_texcoord[0] = texcoord2f;
2170 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2171 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2172 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2173 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2175 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2176 GL_LockArrays(firstvertex, numvertices);
2177 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2178 GL_LockArrays(0, 0);
2180 c_rt_lighttris += numtriangles;
2182 memset(&m, 0, sizeof(m));
2183 m.pointer_vertex = vertex3f;
2184 m.tex[0] = R_GetTexture(basetexture);
2185 m.pointer_texcoord[0] = texcoord2f;
2186 if (r_shadow_lightcubemap != r_texture_whitecube)
2188 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2190 m.pointer_texcoord3f[1] = vertex3f;
2191 m.texmatrix[1] = r_shadow_entitytolight;
2193 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2194 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2197 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2199 // this final code is shared
2201 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2202 VectorScale(lightcolorbase, colorscale, color2);
2203 GL_LockArrays(firstvertex, numvertices);
2204 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2206 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2207 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2209 c_rt_lighttris += numtriangles;
2211 GL_LockArrays(0, 0);
2213 if (specularscale && glosstexture != r_texture_black)
2215 // FIXME: detect blendsquare!
2216 //if (gl_support_blendsquare)
2218 colorscale = specularscale;
2220 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2222 // 2/0/0/1/2 3D combine blendsquare path
2223 memset(&m, 0, sizeof(m));
2224 m.pointer_vertex = vertex3f;
2225 m.tex[0] = R_GetTexture(bumptexture);
2226 m.pointer_texcoord[0] = texcoord2f;
2227 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2228 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2229 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2230 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2232 GL_ColorMask(0,0,0,1);
2233 // this squares the result
2234 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2235 GL_LockArrays(firstvertex, numvertices);
2236 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2237 GL_LockArrays(0, 0);
2239 c_rt_lighttris += numtriangles;
2241 memset(&m, 0, sizeof(m));
2242 m.pointer_vertex = vertex3f;
2244 GL_LockArrays(firstvertex, numvertices);
2245 // square alpha in framebuffer a few times to make it shiny
2246 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2247 // these comments are a test run through this math for intensity 0.5
2248 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2249 // 0.25 * 0.25 = 0.0625 (this is another pass)
2250 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2251 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2253 c_rt_lighttris += numtriangles;
2254 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2256 c_rt_lighttris += numtriangles;
2257 GL_LockArrays(0, 0);
2259 memset(&m, 0, sizeof(m));
2260 m.pointer_vertex = vertex3f;
2261 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2263 m.pointer_texcoord3f[0] = vertex3f;
2264 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2266 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2267 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2270 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2271 GL_LockArrays(firstvertex, numvertices);
2272 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2273 GL_LockArrays(0, 0);
2275 c_rt_lighttris += numtriangles;
2277 memset(&m, 0, sizeof(m));
2278 m.pointer_vertex = vertex3f;
2279 m.tex[0] = R_GetTexture(glosstexture);
2280 m.pointer_texcoord[0] = texcoord2f;
2281 if (r_shadow_lightcubemap != r_texture_whitecube)
2283 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2285 m.pointer_texcoord3f[1] = vertex3f;
2286 m.texmatrix[1] = r_shadow_entitytolight;
2288 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2289 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2292 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2294 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2296 // 2/0/0/2 3D combine blendsquare path
2297 memset(&m, 0, sizeof(m));
2298 m.pointer_vertex = vertex3f;
2299 m.tex[0] = R_GetTexture(bumptexture);
2300 m.pointer_texcoord[0] = texcoord2f;
2301 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2302 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2303 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2304 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2306 GL_ColorMask(0,0,0,1);
2307 // this squares the result
2308 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2309 GL_LockArrays(firstvertex, numvertices);
2310 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2311 GL_LockArrays(0, 0);
2313 c_rt_lighttris += numtriangles;
2315 memset(&m, 0, sizeof(m));
2316 m.pointer_vertex = vertex3f;
2318 GL_LockArrays(firstvertex, numvertices);
2319 // square alpha in framebuffer a few times to make it shiny
2320 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2321 // these comments are a test run through this math for intensity 0.5
2322 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2323 // 0.25 * 0.25 = 0.0625 (this is another pass)
2324 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2325 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2327 c_rt_lighttris += numtriangles;
2328 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2330 c_rt_lighttris += numtriangles;
2331 GL_LockArrays(0, 0);
2333 memset(&m, 0, sizeof(m));
2334 m.pointer_vertex = vertex3f;
2335 m.tex[0] = R_GetTexture(glosstexture);
2336 m.pointer_texcoord[0] = texcoord2f;
2337 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2339 m.pointer_texcoord3f[1] = vertex3f;
2340 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2342 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2343 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2345 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2349 // 2/0/0/2/2 2D combine blendsquare path
2350 memset(&m, 0, sizeof(m));
2351 m.pointer_vertex = vertex3f;
2352 m.tex[0] = R_GetTexture(bumptexture);
2353 m.pointer_texcoord[0] = texcoord2f;
2354 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2355 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2356 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2357 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2359 GL_ColorMask(0,0,0,1);
2360 // this squares the result
2361 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2362 GL_LockArrays(firstvertex, numvertices);
2363 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2364 GL_LockArrays(0, 0);
2366 c_rt_lighttris += numtriangles;
2368 memset(&m, 0, sizeof(m));
2369 m.pointer_vertex = vertex3f;
2371 GL_LockArrays(firstvertex, numvertices);
2372 // square alpha in framebuffer a few times to make it shiny
2373 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2374 // these comments are a test run through this math for intensity 0.5
2375 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2376 // 0.25 * 0.25 = 0.0625 (this is another pass)
2377 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2378 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2380 c_rt_lighttris += numtriangles;
2381 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2383 c_rt_lighttris += numtriangles;
2384 GL_LockArrays(0, 0);
2386 memset(&m, 0, sizeof(m));
2387 m.pointer_vertex = vertex3f;
2388 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2390 m.pointer_texcoord3f[0] = vertex3f;
2391 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2393 m.pointer_texcoord[0] = varray_texcoord2f[0];
2394 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2396 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2398 m.pointer_texcoord3f[1] = vertex3f;
2399 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2401 m.pointer_texcoord[1] = varray_texcoord2f[1];
2402 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2405 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2406 GL_LockArrays(firstvertex, numvertices);
2407 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2408 GL_LockArrays(0, 0);
2410 c_rt_lighttris += numtriangles;
2412 memset(&m, 0, sizeof(m));
2413 m.pointer_vertex = vertex3f;
2414 m.tex[0] = R_GetTexture(glosstexture);
2415 m.pointer_texcoord[0] = texcoord2f;
2416 if (r_shadow_lightcubemap != r_texture_whitecube)
2418 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2420 m.pointer_texcoord3f[1] = vertex3f;
2421 m.texmatrix[1] = r_shadow_entitytolight;
2423 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2424 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2427 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2430 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2431 VectorScale(lightcolorbase, colorscale, color2);
2432 GL_LockArrays(firstvertex, numvertices);
2433 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2435 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2436 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2438 c_rt_lighttris += numtriangles;
2440 GL_LockArrays(0, 0);
2444 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
2446 // TODO: add direct pants/shirt rendering
2447 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2448 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
2449 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2450 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
2451 if (r_shadow_rtlight->ambientscale)
2453 GL_BlendFunc(GL_ONE, GL_ONE);
2454 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
2455 memset(&m, 0, sizeof(m));
2456 m.pointer_vertex = vertex3f;
2457 m.tex[0] = R_GetTexture(basetexture);
2458 m.pointer_texcoord[0] = texcoord2f;
2459 if (r_textureunits.integer >= 2)
2462 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2464 m.pointer_texcoord3f[1] = vertex3f;
2465 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2467 m.pointer_texcoord[1] = varray_texcoord2f[1];
2468 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2470 if (r_textureunits.integer >= 3)
2472 // Geforce3/Radeon class but not using dot3
2473 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2475 m.pointer_texcoord3f[2] = vertex3f;
2476 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2478 m.pointer_texcoord[2] = varray_texcoord2f[2];
2479 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2483 if (r_textureunits.integer >= 3)
2484 m.pointer_color = NULL;
2486 m.pointer_color = varray_color4f;
2488 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2490 color[0] = bound(0, color2[0], 1);
2491 color[1] = bound(0, color2[1], 1);
2492 color[2] = bound(0, color2[2], 1);
2493 if (r_textureunits.integer >= 3)
2494 GL_Color(color[0], color[1], color[2], 1);
2495 else if (r_textureunits.integer >= 2)
2496 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2498 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2499 GL_LockArrays(firstvertex, numvertices);
2500 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2501 GL_LockArrays(0, 0);
2503 c_rt_lighttris += numtriangles;
2506 if (r_shadow_rtlight->diffusescale)
2508 GL_BlendFunc(GL_ONE, GL_ONE);
2509 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
2510 memset(&m, 0, sizeof(m));
2511 m.pointer_vertex = vertex3f;
2512 m.pointer_color = varray_color4f;
2513 m.tex[0] = R_GetTexture(basetexture);
2514 m.pointer_texcoord[0] = texcoord2f;
2515 if (r_textureunits.integer >= 2)
2518 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2520 m.pointer_texcoord3f[1] = vertex3f;
2521 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2523 m.pointer_texcoord[1] = varray_texcoord2f[1];
2524 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2526 if (r_textureunits.integer >= 3)
2528 // Geforce3/Radeon class but not using dot3
2529 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2531 m.pointer_texcoord3f[2] = vertex3f;
2532 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2534 m.pointer_texcoord[2] = varray_texcoord2f[2];
2535 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2540 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2542 color[0] = bound(0, color2[0], 1);
2543 color[1] = bound(0, color2[1], 1);
2544 color[2] = bound(0, color2[2], 1);
2545 if (r_textureunits.integer >= 3)
2546 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2547 else if (r_textureunits.integer >= 2)
2548 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2550 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2551 GL_LockArrays(firstvertex, numvertices);
2552 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2553 GL_LockArrays(0, 0);
2555 c_rt_lighttris += numtriangles;
2561 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2565 R_RTLight_Uncompile(rtlight);
2566 memset(rtlight, 0, sizeof(*rtlight));
2568 VectorCopy(light->origin, rtlight->shadoworigin);
2569 VectorCopy(light->color, rtlight->color);
2570 rtlight->radius = light->radius;
2571 //rtlight->cullradius = rtlight->radius;
2572 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2573 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2574 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2575 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2576 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2577 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2578 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2579 rtlight->cubemapname[0] = 0;
2580 if (light->cubemapname[0])
2581 strcpy(rtlight->cubemapname, light->cubemapname);
2582 else if (light->cubemapnum > 0)
2583 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2584 rtlight->shadow = light->shadow;
2585 rtlight->corona = light->corona;
2586 rtlight->style = light->style;
2587 rtlight->isstatic = isstatic;
2588 rtlight->coronasizescale = light->coronasizescale;
2589 rtlight->ambientscale = light->ambientscale;
2590 rtlight->diffusescale = light->diffusescale;
2591 rtlight->specularscale = light->specularscale;
2592 rtlight->flags = light->flags;
2593 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2594 // ConcatScale won't work here because this needs to scale rotate and
2595 // translate, not just rotate
2596 scale = 1.0f / rtlight->radius;
2597 for (k = 0;k < 3;k++)
2598 for (j = 0;j < 4;j++)
2599 rtlight->matrix_worldtolight.m[k][j] *= scale;
2601 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2602 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2603 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2604 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2607 // compiles rtlight geometry
2608 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2609 void R_RTLight_Compile(rtlight_t *rtlight)
2611 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2612 entity_render_t *ent = r_refdef.worldentity;
2613 model_t *model = r_refdef.worldmodel;
2616 // compile the light
2617 rtlight->compiled = true;
2618 rtlight->static_numleafs = 0;
2619 rtlight->static_numleafpvsbytes = 0;
2620 rtlight->static_leaflist = NULL;
2621 rtlight->static_leafpvs = NULL;
2622 rtlight->static_numsurfaces = 0;
2623 rtlight->static_surfacelist = NULL;
2624 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2625 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2626 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2627 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2628 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2629 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2631 if (model && model->GetLightInfo)
2633 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2634 r_shadow_compilingrtlight = rtlight;
2635 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2636 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);
2637 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2638 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2639 rtlight->static_numleafs = numleafs;
2640 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2641 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2642 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2643 rtlight->static_numsurfaces = numsurfaces;
2644 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2646 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2647 if (numleafpvsbytes)
2648 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2650 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2651 if (model->DrawShadowVolume && rtlight->shadow)
2653 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2654 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2655 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2657 if (model->DrawLight)
2659 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2660 model->DrawLight(ent, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
2661 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2663 // switch back to rendering when DrawShadowVolume or DrawLight is called
2664 r_shadow_compilingrtlight = NULL;
2668 // use smallest available cullradius - box radius or light radius
2669 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2670 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2674 if (rtlight->static_meshchain_shadow)
2677 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2680 shadowtris += mesh->numtriangles;
2686 if (rtlight->static_meshchain_light)
2689 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2692 lighttris += mesh->numtriangles;
2696 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes), %i light 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, lighttris, lightmeshes);
2699 void R_RTLight_Uncompile(rtlight_t *rtlight)
2701 if (rtlight->compiled)
2703 if (rtlight->static_meshchain_shadow)
2704 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2705 rtlight->static_meshchain_shadow = NULL;
2706 if (rtlight->static_meshchain_light)
2707 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2708 rtlight->static_meshchain_light = NULL;
2709 // these allocations are grouped
2710 if (rtlight->static_leaflist)
2711 Mem_Free(rtlight->static_leaflist);
2712 rtlight->static_numleafs = 0;
2713 rtlight->static_numleafpvsbytes = 0;
2714 rtlight->static_leaflist = NULL;
2715 rtlight->static_leafpvs = NULL;
2716 rtlight->static_numsurfaces = 0;
2717 rtlight->static_surfacelist = NULL;
2718 rtlight->compiled = false;
2722 void R_Shadow_UncompileWorldLights(void)
2725 for (light = r_shadow_worldlightchain;light;light = light->next)
2726 R_RTLight_Uncompile(&light->rtlight);
2729 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2731 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2732 vec_t relativeshadowradius;
2733 if (ent == r_refdef.worldentity)
2735 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2738 R_Mesh_Matrix(&ent->matrix);
2739 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2741 R_Mesh_VertexPointer(mesh->vertex3f);
2742 GL_LockArrays(0, mesh->numverts);
2743 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2745 // decrement stencil if backface is behind depthbuffer
2746 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2747 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2748 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2749 c_rtcached_shadowmeshes++;
2750 c_rtcached_shadowtris += mesh->numtriangles;
2751 // increment stencil if frontface is behind depthbuffer
2752 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2753 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2755 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2756 c_rtcached_shadowmeshes++;
2757 c_rtcached_shadowtris += mesh->numtriangles;
2758 GL_LockArrays(0, 0);
2761 else if (numsurfaces)
2763 R_Mesh_Matrix(&ent->matrix);
2764 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2769 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2770 relativeshadowradius = rtlight->radius / ent->scale;
2771 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2772 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2773 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2774 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2775 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2776 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2777 R_Mesh_Matrix(&ent->matrix);
2778 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2782 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2785 // set up properties for rendering light onto this entity
2786 r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2787 r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2788 r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2789 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2790 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2791 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2792 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2793 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2794 R_Mesh_Matrix(&ent->matrix);
2795 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2797 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2798 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2799 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2800 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2802 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2805 if (ent == r_refdef.worldentity)
2807 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2809 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2810 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, r_shadow_entitylightcolor, vec3_origin, vec3_origin, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular);
2813 ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2816 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2819 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2824 int numleafs, numsurfaces;
2825 int *leaflist, *surfacelist;
2827 int numlightentities;
2828 int numshadowentities;
2829 entity_render_t *lightentities[MAX_EDICTS];
2830 entity_render_t *shadowentities[MAX_EDICTS];
2832 // skip lights that don't light (corona only lights)
2833 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2836 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2837 VectorScale(rtlight->color, f, lightcolor);
2838 if (VectorLength2(lightcolor) < 0.01)
2841 if (rtlight->selected)
2843 f = 2 + sin(realtime * M_PI * 4.0);
2844 VectorScale(lightcolor, f, lightcolor);
2848 // loading is done before visibility checks because loading should happen
2849 // all at once at the start of a level, not when it stalls gameplay.
2850 // (especially important to benchmarks)
2852 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2853 R_RTLight_Compile(rtlight);
2855 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2857 // if the light box is offscreen, skip it
2858 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2861 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2863 // compiled light, world available and can receive realtime lighting
2864 // retrieve leaf information
2865 numleafs = rtlight->static_numleafs;
2866 leaflist = rtlight->static_leaflist;
2867 leafpvs = rtlight->static_leafpvs;
2868 numsurfaces = rtlight->static_numsurfaces;
2869 surfacelist = rtlight->static_surfacelist;
2871 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2873 // dynamic light, world available and can receive realtime lighting
2874 // calculate lit surfaces and leafs
2875 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2876 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);
2877 leaflist = r_shadow_buffer_leaflist;
2878 leafpvs = r_shadow_buffer_leafpvs;
2879 surfacelist = r_shadow_buffer_surfacelist;
2880 // if the reduced leaf bounds are offscreen, skip it
2881 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2893 // check if light is illuminating any visible leafs
2896 for (i = 0;i < numleafs;i++)
2897 if (r_worldleafvisible[leaflist[i]])
2902 // set up a scissor rectangle for this light
2903 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2906 numlightentities = 0;
2908 lightentities[numlightentities++] = r_refdef.worldentity;
2909 numshadowentities = 0;
2911 shadowentities[numshadowentities++] = r_refdef.worldentity;
2912 if (r_drawentities.integer)
2914 for (i = 0;i < r_refdef.numentities;i++)
2916 entity_render_t *ent = r_refdef.entities[i];
2917 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2919 && !(ent->flags & RENDER_TRANSPARENT)
2920 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2922 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2923 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2924 shadowentities[numshadowentities++] = ent;
2925 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2926 lightentities[numlightentities++] = ent;
2931 // return if there's nothing at all to light
2932 if (!numlightentities)
2935 R_Shadow_Stage_ActiveLight(rtlight);
2939 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2942 R_Shadow_Stage_StencilShadowVolumes();
2943 for (i = 0;i < numshadowentities;i++)
2944 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2947 if (numlightentities && !visible)
2949 R_Shadow_Stage_Lighting(usestencil);
2950 for (i = 0;i < numlightentities;i++)
2951 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2954 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2956 R_Shadow_Stage_VisibleShadowVolumes();
2957 for (i = 0;i < numshadowentities;i++)
2958 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2961 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2963 R_Shadow_Stage_VisibleLighting(usestencil);
2964 for (i = 0;i < numlightentities;i++)
2965 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2969 void R_ShadowVolumeLighting(qboolean visible)
2974 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2975 R_Shadow_EditLights_Reload_f();
2977 R_Shadow_Stage_Begin();
2979 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2980 if (r_shadow_debuglight.integer >= 0)
2982 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2983 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2984 R_DrawRTLight(&light->rtlight, visible);
2987 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2988 if (light->flags & flag)
2989 R_DrawRTLight(&light->rtlight, visible);
2991 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2992 R_DrawRTLight(&light->rtlight, visible);
2994 R_Shadow_Stage_End();
2997 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2998 typedef struct suffixinfo_s
3001 qboolean flipx, flipy, flipdiagonal;
3004 static suffixinfo_t suffix[3][6] =
3007 {"px", false, false, false},
3008 {"nx", false, false, false},
3009 {"py", false, false, false},
3010 {"ny", false, false, false},
3011 {"pz", false, false, false},
3012 {"nz", false, false, false}
3015 {"posx", false, false, false},
3016 {"negx", false, false, false},
3017 {"posy", false, false, false},
3018 {"negy", false, false, false},
3019 {"posz", false, false, false},
3020 {"negz", false, false, false}
3023 {"rt", true, false, true},
3024 {"lf", false, true, true},
3025 {"ft", true, true, false},
3026 {"bk", false, false, false},
3027 {"up", true, false, true},
3028 {"dn", true, false, true}
3032 static int componentorder[4] = {0, 1, 2, 3};
3034 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3036 int i, j, cubemapsize;
3037 qbyte *cubemappixels, *image_rgba;
3038 rtexture_t *cubemaptexture;
3040 // must start 0 so the first loadimagepixels has no requested width/height
3042 cubemappixels = NULL;
3043 cubemaptexture = NULL;
3044 // keep trying different suffix groups (posx, px, rt) until one loads
3045 for (j = 0;j < 3 && !cubemappixels;j++)
3047 // load the 6 images in the suffix group
3048 for (i = 0;i < 6;i++)
3050 // generate an image name based on the base and and suffix
3051 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3053 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3055 // an image loaded, make sure width and height are equal
3056 if (image_width == image_height)
3058 // if this is the first image to load successfully, allocate the cubemap memory
3059 if (!cubemappixels && image_width >= 1)
3061 cubemapsize = image_width;
3062 // note this clears to black, so unavailable sides are black
3063 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3065 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3067 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);
3070 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3072 Mem_Free(image_rgba);
3076 // if a cubemap loaded, upload it
3079 if (!r_shadow_filters_texturepool)
3080 r_shadow_filters_texturepool = R_AllocTexturePool();
3081 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3082 Mem_Free(cubemappixels);
3086 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3087 for (j = 0;j < 3;j++)
3088 for (i = 0;i < 6;i++)
3089 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3090 Con_Print(" and was unable to find any of them.\n");
3092 return cubemaptexture;
3095 rtexture_t *R_Shadow_Cubemap(const char *basename)
3098 for (i = 0;i < numcubemaps;i++)
3099 if (!strcasecmp(cubemaps[i].basename, basename))
3100 return cubemaps[i].texture;
3101 if (i >= MAX_CUBEMAPS)
3102 return r_texture_whitecube;
3104 strcpy(cubemaps[i].basename, basename);
3105 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3106 return cubemaps[i].texture;
3109 void R_Shadow_FreeCubemaps(void)
3112 R_FreeTexturePool(&r_shadow_filters_texturepool);
3115 dlight_t *R_Shadow_NewWorldLight(void)
3118 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3119 light->next = r_shadow_worldlightchain;
3120 r_shadow_worldlightchain = light;
3124 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)
3126 VectorCopy(origin, light->origin);
3127 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3128 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3129 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3130 light->color[0] = max(color[0], 0);
3131 light->color[1] = max(color[1], 0);
3132 light->color[2] = max(color[2], 0);
3133 light->radius = max(radius, 0);
3134 light->style = style;
3135 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3137 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3140 light->shadow = shadowenable;
3141 light->corona = corona;
3144 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3145 light->coronasizescale = coronasizescale;
3146 light->ambientscale = ambientscale;
3147 light->diffusescale = diffusescale;
3148 light->specularscale = specularscale;
3149 light->flags = flags;
3150 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3152 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3155 void R_Shadow_FreeWorldLight(dlight_t *light)
3157 dlight_t **lightpointer;
3158 R_RTLight_Uncompile(&light->rtlight);
3159 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3160 if (*lightpointer != light)
3161 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3162 *lightpointer = light->next;
3166 void R_Shadow_ClearWorldLights(void)
3168 while (r_shadow_worldlightchain)
3169 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3170 r_shadow_selectedlight = NULL;
3171 R_Shadow_FreeCubemaps();
3174 void R_Shadow_SelectLight(dlight_t *light)
3176 if (r_shadow_selectedlight)
3177 r_shadow_selectedlight->selected = false;
3178 r_shadow_selectedlight = light;
3179 if (r_shadow_selectedlight)
3180 r_shadow_selectedlight->selected = true;
3183 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3185 float scale = r_editlights_cursorgrid.value * 0.5f;
3186 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
3189 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3192 const dlight_t *light;
3195 if (light->selected)
3196 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3199 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
3202 void R_Shadow_DrawLightSprites(void)
3208 for (i = 0;i < 5;i++)
3210 lighttextures[i] = NULL;
3211 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3212 lighttextures[i] = pic->tex;
3215 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3216 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3217 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3220 void R_Shadow_SelectLightInView(void)
3222 float bestrating, rating, temp[3];
3223 dlight_t *best, *light;
3226 for (light = r_shadow_worldlightchain;light;light = light->next)
3228 VectorSubtract(light->origin, r_vieworigin, temp);
3229 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3232 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3233 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3235 bestrating = rating;
3240 R_Shadow_SelectLight(best);
3243 void R_Shadow_LoadWorldLights(void)
3245 int n, a, style, shadow, flags;
3246 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3247 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3248 if (r_refdef.worldmodel == NULL)
3250 Con_Print("No map loaded.\n");
3253 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3254 strlcat (name, ".rtlights", sizeof (name));
3255 lightsstring = FS_LoadFile(name, tempmempool, false);
3265 for (;COM_Parse(t, true) && strcmp(
3266 if (COM_Parse(t, true))
3268 if (com_token[0] == '!')
3271 origin[0] = atof(com_token+1);
3274 origin[0] = atof(com_token);
3279 while (*s && *s != '\n' && *s != '\r')
3285 // check for modifier flags
3292 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);
3295 flags = LIGHTFLAG_REALTIMEMODE;
3303 coronasizescale = 0.25f;
3305 VectorClear(angles);
3308 if (a < 9 || !strcmp(cubemapname, "\"\""))
3310 // remove quotes on cubemapname
3311 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3313 cubemapname[strlen(cubemapname)-1] = 0;
3314 strcpy(cubemapname, cubemapname + 1);
3318 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);
3321 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3322 radius *= r_editlights_rtlightssizescale.value;
3323 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3331 Con_Printf("invalid rtlights file \"%s\"\n", name);
3332 Mem_Free(lightsstring);
3336 void R_Shadow_SaveWorldLights(void)
3339 int bufchars, bufmaxchars;
3341 char name[MAX_QPATH];
3343 if (!r_shadow_worldlightchain)
3345 if (r_refdef.worldmodel == NULL)
3347 Con_Print("No map loaded.\n");
3350 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3351 strlcat (name, ".rtlights", sizeof (name));
3352 bufchars = bufmaxchars = 0;
3354 for (light = r_shadow_worldlightchain;light;light = light->next)
3356 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3357 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 / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, 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);
3358 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3359 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 / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3361 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 / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
3362 if (bufchars + (int) strlen(line) > bufmaxchars)
3364 bufmaxchars = bufchars + strlen(line) + 2048;
3366 buf = Mem_Alloc(tempmempool, bufmaxchars);
3370 memcpy(buf, oldbuf, bufchars);
3376 memcpy(buf + bufchars, line, strlen(line));
3377 bufchars += strlen(line);
3381 FS_WriteFile(name, buf, bufchars);
3386 void R_Shadow_LoadLightsFile(void)
3389 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3390 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3391 if (r_refdef.worldmodel == NULL)
3393 Con_Print("No map loaded.\n");
3396 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3397 strlcat (name, ".lights", sizeof (name));
3398 lightsstring = FS_LoadFile(name, tempmempool, false);
3406 while (*s && *s != '\n' && *s != '\r')
3412 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);
3416 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);
3419 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3420 radius = bound(15, radius, 4096);
3421 VectorScale(color, (2.0f / (8388608.0f)), color);
3422 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3430 Con_Printf("invalid lights file \"%s\"\n", name);
3431 Mem_Free(lightsstring);
3435 // tyrlite/hmap2 light types in the delay field
3436 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3438 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3440 int entnum, style, islight, skin, pflags, effects, type, n;
3443 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3444 char key[256], value[1024];
3446 if (r_refdef.worldmodel == NULL)
3448 Con_Print("No map loaded.\n");
3451 // try to load a .ent file first
3452 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3453 strlcat (key, ".ent", sizeof (key));
3454 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3455 // and if that is not found, fall back to the bsp file entity string
3457 data = r_refdef.worldmodel->brush.entities;
3460 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3462 type = LIGHTTYPE_MINUSX;
3463 origin[0] = origin[1] = origin[2] = 0;
3464 originhack[0] = originhack[1] = originhack[2] = 0;
3465 angles[0] = angles[1] = angles[2] = 0;
3466 color[0] = color[1] = color[2] = 1;
3467 light[0] = light[1] = light[2] = 1;light[3] = 300;
3468 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3478 if (!COM_ParseToken(&data, false))
3480 if (com_token[0] == '}')
3481 break; // end of entity
3482 if (com_token[0] == '_')
3483 strcpy(key, com_token + 1);
3485 strcpy(key, com_token);
3486 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3487 key[strlen(key)-1] = 0;
3488 if (!COM_ParseToken(&data, false))
3490 strcpy(value, com_token);
3492 // now that we have the key pair worked out...
3493 if (!strcmp("light", key))
3495 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3499 light[0] = vec[0] * (1.0f / 256.0f);
3500 light[1] = vec[0] * (1.0f / 256.0f);
3501 light[2] = vec[0] * (1.0f / 256.0f);
3507 light[0] = vec[0] * (1.0f / 255.0f);
3508 light[1] = vec[1] * (1.0f / 255.0f);
3509 light[2] = vec[2] * (1.0f / 255.0f);
3513 else if (!strcmp("delay", key))
3515 else if (!strcmp("origin", key))
3516 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3517 else if (!strcmp("angle", key))
3518 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3519 else if (!strcmp("angles", key))
3520 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3521 else if (!strcmp("color", key))
3522 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3523 else if (!strcmp("wait", key))
3524 fadescale = atof(value);
3525 else if (!strcmp("classname", key))
3527 if (!strncmp(value, "light", 5))
3530 if (!strcmp(value, "light_fluoro"))
3535 overridecolor[0] = 1;
3536 overridecolor[1] = 1;
3537 overridecolor[2] = 1;
3539 if (!strcmp(value, "light_fluorospark"))
3544 overridecolor[0] = 1;
3545 overridecolor[1] = 1;
3546 overridecolor[2] = 1;
3548 if (!strcmp(value, "light_globe"))
3553 overridecolor[0] = 1;
3554 overridecolor[1] = 0.8;
3555 overridecolor[2] = 0.4;
3557 if (!strcmp(value, "light_flame_large_yellow"))
3562 overridecolor[0] = 1;
3563 overridecolor[1] = 0.5;
3564 overridecolor[2] = 0.1;
3566 if (!strcmp(value, "light_flame_small_yellow"))
3571 overridecolor[0] = 1;
3572 overridecolor[1] = 0.5;
3573 overridecolor[2] = 0.1;
3575 if (!strcmp(value, "light_torch_small_white"))
3580 overridecolor[0] = 1;
3581 overridecolor[1] = 0.5;
3582 overridecolor[2] = 0.1;
3584 if (!strcmp(value, "light_torch_small_walltorch"))
3589 overridecolor[0] = 1;
3590 overridecolor[1] = 0.5;
3591 overridecolor[2] = 0.1;
3595 else if (!strcmp("style", key))
3596 style = atoi(value);
3597 else if (r_refdef.worldmodel->type == mod_brushq3)
3599 if (!strcmp("scale", key))
3600 lightscale = atof(value);
3601 if (!strcmp("fade", key))
3602 fadescale = atof(value);
3604 else if (!strcmp("skin", key))
3605 skin = (int)atof(value);
3606 else if (!strcmp("pflags", key))
3607 pflags = (int)atof(value);
3608 else if (!strcmp("effects", key))
3609 effects = (int)atof(value);
3613 if (lightscale <= 0)
3617 if (color[0] == color[1] && color[0] == color[2])
3619 color[0] *= overridecolor[0];
3620 color[1] *= overridecolor[1];
3621 color[2] *= overridecolor[2];
3623 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3624 color[0] = color[0] * light[0];
3625 color[1] = color[1] * light[1];
3626 color[2] = color[2] * light[2];
3629 case LIGHTTYPE_MINUSX:
3631 case LIGHTTYPE_RECIPX:
3633 VectorScale(color, (1.0f / 16.0f), color);
3635 case LIGHTTYPE_RECIPXX:
3637 VectorScale(color, (1.0f / 16.0f), color);
3640 case LIGHTTYPE_NONE:
3644 case LIGHTTYPE_MINUSXX:
3647 VectorAdd(origin, originhack, origin);
3649 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);
3652 Mem_Free(entfiledata);
3656 void R_Shadow_SetCursorLocationForView(void)
3659 vec3_t dest, endpos;
3661 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3662 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3663 if (trace.fraction < 1)
3665 dist = trace.fraction * r_editlights_cursordistance.value;
3666 push = r_editlights_cursorpushback.value;
3670 VectorMA(trace.endpos, push, r_viewforward, endpos);
3671 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3673 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3674 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3675 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3678 void R_Shadow_UpdateWorldLightSelection(void)
3680 if (r_editlights.integer)
3682 R_Shadow_SetCursorLocationForView();
3683 R_Shadow_SelectLightInView();
3684 R_Shadow_DrawLightSprites();
3687 R_Shadow_SelectLight(NULL);
3690 void R_Shadow_EditLights_Clear_f(void)
3692 R_Shadow_ClearWorldLights();
3695 void R_Shadow_EditLights_Reload_f(void)
3697 if (!r_refdef.worldmodel)
3699 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3700 R_Shadow_ClearWorldLights();
3701 R_Shadow_LoadWorldLights();
3702 if (r_shadow_worldlightchain == NULL)
3704 R_Shadow_LoadLightsFile();
3705 if (r_shadow_worldlightchain == NULL)
3706 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3710 void R_Shadow_EditLights_Save_f(void)
3712 if (!r_refdef.worldmodel)
3714 R_Shadow_SaveWorldLights();
3717 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3719 R_Shadow_ClearWorldLights();
3720 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3723 void R_Shadow_EditLights_ImportLightsFile_f(void)
3725 R_Shadow_ClearWorldLights();
3726 R_Shadow_LoadLightsFile();
3729 void R_Shadow_EditLights_Spawn_f(void)
3732 if (!r_editlights.integer)
3734 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3737 if (Cmd_Argc() != 1)
3739 Con_Print("r_editlights_spawn does not take parameters\n");
3742 color[0] = color[1] = color[2] = 1;
3743 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3746 void R_Shadow_EditLights_Edit_f(void)
3748 vec3_t origin, angles, color;
3749 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3750 int style, shadows, flags, normalmode, realtimemode;
3751 char cubemapname[1024];
3752 if (!r_editlights.integer)
3754 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3757 if (!r_shadow_selectedlight)
3759 Con_Print("No selected light.\n");
3762 VectorCopy(r_shadow_selectedlight->origin, origin);
3763 VectorCopy(r_shadow_selectedlight->angles, angles);
3764 VectorCopy(r_shadow_selectedlight->color, color);
3765 radius = r_shadow_selectedlight->radius;
3766 style = r_shadow_selectedlight->style;
3767 if (r_shadow_selectedlight->cubemapname)
3768 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3771 shadows = r_shadow_selectedlight->shadow;
3772 corona = r_shadow_selectedlight->corona;
3773 coronasizescale = r_shadow_selectedlight->coronasizescale;
3774 ambientscale = r_shadow_selectedlight->ambientscale;
3775 diffusescale = r_shadow_selectedlight->diffusescale;
3776 specularscale = r_shadow_selectedlight->specularscale;
3777 flags = r_shadow_selectedlight->flags;
3778 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3779 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3780 if (!strcmp(Cmd_Argv(1), "origin"))
3782 if (Cmd_Argc() != 5)
3784 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3787 origin[0] = atof(Cmd_Argv(2));
3788 origin[1] = atof(Cmd_Argv(3));
3789 origin[2] = atof(Cmd_Argv(4));
3791 else if (!strcmp(Cmd_Argv(1), "originx"))
3793 if (Cmd_Argc() != 3)
3795 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3798 origin[0] = atof(Cmd_Argv(2));
3800 else if (!strcmp(Cmd_Argv(1), "originy"))
3802 if (Cmd_Argc() != 3)
3804 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3807 origin[1] = atof(Cmd_Argv(2));
3809 else if (!strcmp(Cmd_Argv(1), "originz"))
3811 if (Cmd_Argc() != 3)
3813 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3816 origin[2] = atof(Cmd_Argv(2));
3818 else if (!strcmp(Cmd_Argv(1), "move"))
3820 if (Cmd_Argc() != 5)
3822 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3825 origin[0] += atof(Cmd_Argv(2));
3826 origin[1] += atof(Cmd_Argv(3));
3827 origin[2] += atof(Cmd_Argv(4));
3829 else if (!strcmp(Cmd_Argv(1), "movex"))
3831 if (Cmd_Argc() != 3)
3833 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3836 origin[0] += atof(Cmd_Argv(2));
3838 else if (!strcmp(Cmd_Argv(1), "movey"))
3840 if (Cmd_Argc() != 3)
3842 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3845 origin[1] += atof(Cmd_Argv(2));
3847 else if (!strcmp(Cmd_Argv(1), "movez"))
3849 if (Cmd_Argc() != 3)
3851 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3854 origin[2] += atof(Cmd_Argv(2));
3856 else if (!strcmp(Cmd_Argv(1), "angles"))
3858 if (Cmd_Argc() != 5)
3860 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3863 angles[0] = atof(Cmd_Argv(2));
3864 angles[1] = atof(Cmd_Argv(3));
3865 angles[2] = atof(Cmd_Argv(4));
3867 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3869 if (Cmd_Argc() != 3)
3871 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3874 angles[0] = atof(Cmd_Argv(2));
3876 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3878 if (Cmd_Argc() != 3)
3880 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3883 angles[1] = atof(Cmd_Argv(2));
3885 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3887 if (Cmd_Argc() != 3)
3889 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3892 angles[2] = atof(Cmd_Argv(2));
3894 else if (!strcmp(Cmd_Argv(1), "color"))
3896 if (Cmd_Argc() != 5)
3898 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3901 color[0] = atof(Cmd_Argv(2));
3902 color[1] = atof(Cmd_Argv(3));
3903 color[2] = atof(Cmd_Argv(4));
3905 else if (!strcmp(Cmd_Argv(1), "radius"))
3907 if (Cmd_Argc() != 3)
3909 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3912 radius = atof(Cmd_Argv(2));
3914 else if (!strcmp(Cmd_Argv(1), "style"))
3916 if (Cmd_Argc() != 3)
3918 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3921 style = atoi(Cmd_Argv(2));
3923 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3927 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3930 if (Cmd_Argc() == 3)
3931 strcpy(cubemapname, Cmd_Argv(2));
3935 else if (!strcmp(Cmd_Argv(1), "shadows"))
3937 if (Cmd_Argc() != 3)
3939 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3942 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3944 else if (!strcmp(Cmd_Argv(1), "corona"))
3946 if (Cmd_Argc() != 3)
3948 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3951 corona = atof(Cmd_Argv(2));
3953 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3955 if (Cmd_Argc() != 3)
3957 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3960 coronasizescale = atof(Cmd_Argv(2));
3962 else if (!strcmp(Cmd_Argv(1), "ambient"))
3964 if (Cmd_Argc() != 3)
3966 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3969 ambientscale = atof(Cmd_Argv(2));
3971 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3973 if (Cmd_Argc() != 3)
3975 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3978 diffusescale = atof(Cmd_Argv(2));
3980 else if (!strcmp(Cmd_Argv(1), "specular"))
3982 if (Cmd_Argc() != 3)
3984 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3987 specularscale = atof(Cmd_Argv(2));
3989 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3991 if (Cmd_Argc() != 3)
3993 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3996 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3998 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4000 if (Cmd_Argc() != 3)
4002 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4005 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4009 Con_Print("usage: r_editlights_edit [property] [value]\n");
4010 Con_Print("Selected light's properties:\n");
4011 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4012 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4013 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4014 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4015 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4016 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4017 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4018 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4019 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4020 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4021 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4022 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4023 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4024 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4027 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4028 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4031 void R_Shadow_EditLights_EditAll_f(void)
4035 if (!r_editlights.integer)
4037 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4041 for (light = r_shadow_worldlightchain;light;light = light->next)
4043 R_Shadow_SelectLight(light);
4044 R_Shadow_EditLights_Edit_f();
4048 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4050 int lightnumber, lightcount;
4054 if (!r_editlights.integer)
4060 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4061 if (light == r_shadow_selectedlight)
4062 lightnumber = lightcount;
4063 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;
4064 if (r_shadow_selectedlight == NULL)
4066 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4067 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;
4068 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;
4069 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;
4070 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4071 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4072 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4073 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;
4074 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4075 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4076 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4077 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4078 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4079 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;
4080 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;
4083 void R_Shadow_EditLights_ToggleShadow_f(void)
4085 if (!r_editlights.integer)
4087 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4090 if (!r_shadow_selectedlight)
4092 Con_Print("No selected light.\n");
4095 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);
4098 void R_Shadow_EditLights_ToggleCorona_f(void)
4100 if (!r_editlights.integer)
4102 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4105 if (!r_shadow_selectedlight)
4107 Con_Print("No selected light.\n");
4110 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);
4113 void R_Shadow_EditLights_Remove_f(void)
4115 if (!r_editlights.integer)
4117 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4120 if (!r_shadow_selectedlight)
4122 Con_Print("No selected light.\n");
4125 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4126 r_shadow_selectedlight = NULL;
4129 void R_Shadow_EditLights_Help_f(void)
4132 "Documentation on r_editlights system:\n"
4134 "r_editlights : enable/disable editing mode\n"
4135 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4136 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4137 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4138 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4139 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4140 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4141 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4143 "r_editlights_help : this help\n"
4144 "r_editlights_clear : remove all lights\n"
4145 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4146 "r_editlights_save : save to .rtlights file\n"
4147 "r_editlights_spawn : create a light with default settings\n"
4148 "r_editlights_edit command : edit selected light - more documentation below\n"
4149 "r_editlights_remove : remove selected light\n"
4150 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4151 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4152 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4154 "origin x y z : set light location\n"
4155 "originx x: set x component of light location\n"
4156 "originy y: set y component of light location\n"
4157 "originz z: set z component of light location\n"
4158 "move x y z : adjust light location\n"
4159 "movex x: adjust x component of light location\n"
4160 "movey y: adjust y component of light location\n"
4161 "movez z: adjust z component of light location\n"
4162 "angles x y z : set light angles\n"
4163 "anglesx x: set x component of light angles\n"
4164 "anglesy y: set y component of light angles\n"
4165 "anglesz z: set z component of light angles\n"
4166 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4167 "radius radius : set radius (size) of light\n"
4168 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4169 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4170 "shadows 1/0 : turn on/off shadows\n"
4171 "corona n : set corona intensity\n"
4172 "coronasize n : set corona size (0-1)\n"
4173 "ambient n : set ambient intensity (0-1)\n"
4174 "diffuse n : set diffuse intensity (0-1)\n"
4175 "specular n : set specular intensity (0-1)\n"
4176 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4177 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4178 "<nothing> : print light properties to console\n"
4182 void R_Shadow_EditLights_CopyInfo_f(void)
4184 if (!r_editlights.integer)
4186 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4189 if (!r_shadow_selectedlight)
4191 Con_Print("No selected light.\n");
4194 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4195 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4196 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4197 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4198 if (r_shadow_selectedlight->cubemapname)
4199 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4201 r_shadow_bufferlight.cubemapname[0] = 0;
4202 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4203 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4204 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4205 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4206 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4207 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4208 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4211 void R_Shadow_EditLights_PasteInfo_f(void)
4213 if (!r_editlights.integer)
4215 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4218 if (!r_shadow_selectedlight)
4220 Con_Print("No selected light.\n");
4223 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);
4226 void R_Shadow_EditLights_Init(void)
4228 Cvar_RegisterVariable(&r_editlights);
4229 Cvar_RegisterVariable(&r_editlights_cursordistance);
4230 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4231 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4232 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4233 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4234 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4235 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4236 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4237 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4238 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4239 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4240 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4241 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4242 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4243 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4244 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4245 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4246 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4247 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4248 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4249 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);