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 rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numleafpvsbytes;
146 qbyte *r_shadow_buffer_leafpvs;
147 int *r_shadow_buffer_leaflist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_attenuation2dtexture;
155 rtexture_t *r_shadow_attenuation3dtexture;
157 // lights are reloaded when this changes
158 char r_shadow_mapname[MAX_QPATH];
160 // used only for light filters (cubemaps)
161 rtexturepool_t *r_shadow_filters_texturepool;
163 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
164 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
165 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
166 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
167 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
168 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
169 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
170 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
171 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
172 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
173 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
174 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
175 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
176 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
177 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
178 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
179 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
180 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
181 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
182 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
183 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
184 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
187 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
188 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
189 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
190 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
191 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
192 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
193 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
194 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
195 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
196 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
197 cvar_t r_editlights = {0, "r_editlights", "0"};
198 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
199 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
200 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
201 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
202 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
203 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
204 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
206 float r_shadow_attenpower, r_shadow_attenscale;
208 rtlight_t *r_shadow_compilingrtlight;
209 dlight_t *r_shadow_worldlightchain;
210 dlight_t *r_shadow_selectedlight;
211 dlight_t r_shadow_bufferlight;
212 vec3_t r_editlights_cursorlocation;
214 rtexture_t *lighttextures[5];
216 extern int con_vislines;
218 typedef struct cubemapinfo_s
225 #define MAX_CUBEMAPS 256
226 static int numcubemaps;
227 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
229 #define SHADERPERMUTATION_SPECULAR (1<<0)
230 #define SHADERPERMUTATION_FOG (1<<1)
231 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
232 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
233 #define SHADERPERMUTATION_COUNT (1<<4)
235 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
237 void R_Shadow_UncompileWorldLights(void);
238 void R_Shadow_ClearWorldLights(void);
239 void R_Shadow_SaveWorldLights(void);
240 void R_Shadow_LoadWorldLights(void);
241 void R_Shadow_LoadLightsFile(void);
242 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
243 void R_Shadow_EditLights_Reload_f(void);
244 void R_Shadow_ValidateCvars(void);
245 static void R_Shadow_MakeTextures(void);
246 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
248 const char *builtinshader_light_vert =
249 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
250 "// written by Forest 'LordHavoc' Hale\n"
252 "uniform vec3 LightPosition;\n"
254 "varying vec2 TexCoord;\n"
255 "varying vec3 CubeVector;\n"
256 "varying vec3 LightVector;\n"
258 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
259 "uniform vec3 EyePosition;\n"
260 "varying vec3 EyeVector;\n"
263 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
267 " // copy the surface texcoord\n"
268 " TexCoord = gl_MultiTexCoord0.st;\n"
270 " // transform vertex position into light attenuation/cubemap space\n"
271 " // (-1 to +1 across the light box)\n"
272 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
274 " // transform unnormalized light direction into tangent space\n"
275 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
276 " // normalize it per pixel)\n"
277 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
278 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
279 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
280 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
282 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
283 " // transform unnormalized eye direction into tangent space\n"
284 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
285 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
286 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
287 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
290 " // transform vertex to camera space, using ftransform to match non-VS\n"
292 " gl_Position = ftransform();\n"
296 const char *builtinshader_light_frag =
297 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
298 "// written by Forest 'LordHavoc' Hale\n"
300 "uniform vec3 LightColor;\n"
302 "#ifdef USEOFFSETMAPPING\n"
303 "uniform float OffsetMapping_Scale;\n"
304 "uniform float OffsetMapping_Bias;\n"
306 "#ifdef USESPECULAR\n"
307 "uniform float SpecularPower;\n"
310 "uniform float FogRangeRecip;\n"
312 "uniform float AmbientScale;\n"
313 "uniform float DiffuseScale;\n"
314 "#ifdef USESPECULAR\n"
315 "uniform float SpecularScale;\n"
318 "uniform sampler2D Texture_Normal;\n"
319 "uniform sampler2D Texture_Color;\n"
320 "#ifdef USESPECULAR\n"
321 "uniform sampler2D Texture_Gloss;\n"
323 "#ifdef USECUBEFILTER\n"
324 "uniform samplerCube Texture_Cube;\n"
327 "uniform sampler2D Texture_FogMask;\n"
330 "varying vec2 TexCoord;\n"
331 "varying vec3 CubeVector;\n"
332 "varying vec3 LightVector;\n"
333 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
334 "varying vec3 EyeVector;\n"
341 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
342 " // center and sharp falloff at the edge, this is about the most efficient\n"
343 " // we can get away with as far as providing illumination.\n"
345 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
346 " // provide significant illumination, large = slow = pain.\n"
347 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
351 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
354 "#ifdef USEOFFSETMAPPING\n"
355 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
356 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
357 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
358 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
359 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
360 "#define TexCoord TexCoordOffset\n"
363 " // get the texels - with a blendmap we'd need to blend multiple here\n"
364 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
365 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
366 "#ifdef USESPECULAR\n"
367 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
370 " // calculate shading\n"
371 " vec3 diffusenormal = normalize(LightVector);\n"
372 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
373 "#ifdef USESPECULAR\n"
374 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
377 "#ifdef USECUBEFILTER\n"
378 " // apply light cubemap filter\n"
379 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
382 " // calculate fragment color\n"
383 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
387 void r_shadow_start(void)
390 // allocate vertex processing arrays
392 r_shadow_attenuation2dtexture = NULL;
393 r_shadow_attenuation3dtexture = NULL;
394 r_shadow_texturepool = NULL;
395 r_shadow_filters_texturepool = NULL;
396 R_Shadow_ValidateCvars();
397 R_Shadow_MakeTextures();
398 maxshadowelements = 0;
399 shadowelements = NULL;
407 shadowmarklist = NULL;
409 r_shadow_buffer_numleafpvsbytes = 0;
410 r_shadow_buffer_leafpvs = NULL;
411 r_shadow_buffer_leaflist = NULL;
412 r_shadow_buffer_numsurfacepvsbytes = 0;
413 r_shadow_buffer_surfacepvs = NULL;
414 r_shadow_buffer_surfacelist = NULL;
415 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
416 r_shadow_program_light[i] = 0;
417 if (gl_support_fragment_shader)
419 char *vertstring, *fragstring;
420 int vertstrings_count;
421 int fragstrings_count;
422 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
423 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
424 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
425 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
426 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
428 vertstrings_count = 0;
429 fragstrings_count = 0;
430 if (i & SHADERPERMUTATION_SPECULAR)
432 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
433 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
435 if (i & SHADERPERMUTATION_FOG)
437 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
438 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
440 if (i & SHADERPERMUTATION_CUBEFILTER)
442 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
443 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
445 if (i & SHADERPERMUTATION_OFFSETMAPPING)
447 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
448 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
450 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
451 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
452 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
453 if (!r_shadow_program_light[i])
455 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");
458 qglUseProgramObjectARB(r_shadow_program_light[i]);
459 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
460 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
461 if (i & SHADERPERMUTATION_SPECULAR)
463 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
465 if (i & SHADERPERMUTATION_CUBEFILTER)
467 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
469 if (i & SHADERPERMUTATION_FOG)
471 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
474 qglUseProgramObjectARB(0);
476 Mem_Free(fragstring);
478 Mem_Free(vertstring);
482 void r_shadow_shutdown(void)
485 R_Shadow_UncompileWorldLights();
486 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
488 if (r_shadow_program_light[i])
490 GL_Backend_FreeProgram(r_shadow_program_light[i]);
491 r_shadow_program_light[i] = 0;
495 r_shadow_attenuation2dtexture = NULL;
496 r_shadow_attenuation3dtexture = NULL;
497 R_FreeTexturePool(&r_shadow_texturepool);
498 R_FreeTexturePool(&r_shadow_filters_texturepool);
499 maxshadowelements = 0;
501 Mem_Free(shadowelements);
502 shadowelements = NULL;
505 Mem_Free(vertexupdate);
508 Mem_Free(vertexremap);
514 Mem_Free(shadowmark);
517 Mem_Free(shadowmarklist);
518 shadowmarklist = NULL;
520 r_shadow_buffer_numleafpvsbytes = 0;
521 if (r_shadow_buffer_leafpvs)
522 Mem_Free(r_shadow_buffer_leafpvs);
523 r_shadow_buffer_leafpvs = NULL;
524 if (r_shadow_buffer_leaflist)
525 Mem_Free(r_shadow_buffer_leaflist);
526 r_shadow_buffer_leaflist = NULL;
527 r_shadow_buffer_numsurfacepvsbytes = 0;
528 if (r_shadow_buffer_surfacepvs)
529 Mem_Free(r_shadow_buffer_surfacepvs);
530 r_shadow_buffer_surfacepvs = NULL;
531 if (r_shadow_buffer_surfacelist)
532 Mem_Free(r_shadow_buffer_surfacelist);
533 r_shadow_buffer_surfacelist = NULL;
536 void r_shadow_newmap(void)
540 void R_Shadow_Help_f(void)
543 "Documentation on r_shadow system:\n"
545 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
546 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
547 "r_shadow_debuglight : render only this light number (-1 = all)\n"
548 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
549 "r_shadow_gloss2intensity : brightness of forced gloss\n"
550 "r_shadow_glossintensity : brightness of textured gloss\n"
551 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
552 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
553 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
554 "r_shadow_portallight : use portal visibility for static light precomputation\n"
555 "r_shadow_projectdistance : shadow volume projection distance\n"
556 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
557 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
558 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
559 "r_shadow_realtime_world : use high quality world lighting mode\n"
560 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
561 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
562 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
563 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
564 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
565 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
566 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
567 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
568 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
569 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
570 "r_shadow_scissor : use scissor optimization\n"
571 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
572 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
573 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
574 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
575 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
576 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
578 "r_shadow_help : this help\n"
582 void R_Shadow_Init(void)
584 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
585 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
586 Cvar_RegisterVariable(&r_shadow_cull);
587 Cvar_RegisterVariable(&r_shadow_debuglight);
588 Cvar_RegisterVariable(&r_shadow_gloss);
589 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
590 Cvar_RegisterVariable(&r_shadow_glossintensity);
591 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
592 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
593 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
594 Cvar_RegisterVariable(&r_shadow_portallight);
595 Cvar_RegisterVariable(&r_shadow_projectdistance);
596 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
597 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
598 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
599 Cvar_RegisterVariable(&r_shadow_realtime_world);
600 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
601 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
602 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
603 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
604 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
605 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
606 Cvar_RegisterVariable(&r_shadow_scissor);
607 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
608 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
609 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
610 Cvar_RegisterVariable(&r_shadow_texture3d);
611 Cvar_RegisterVariable(&r_shadow_visiblelighting);
612 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
613 Cvar_RegisterVariable(&r_shadow_glsl);
614 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
615 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
616 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
617 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
618 if (gamemode == GAME_TENEBRAE)
620 Cvar_SetValue("r_shadow_gloss", 2);
621 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
623 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
624 R_Shadow_EditLights_Init();
625 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
626 r_shadow_worldlightchain = NULL;
627 maxshadowelements = 0;
628 shadowelements = NULL;
636 shadowmarklist = NULL;
638 r_shadow_buffer_numleafpvsbytes = 0;
639 r_shadow_buffer_leafpvs = NULL;
640 r_shadow_buffer_leaflist = NULL;
641 r_shadow_buffer_numsurfacepvsbytes = 0;
642 r_shadow_buffer_surfacepvs = NULL;
643 r_shadow_buffer_surfacelist = NULL;
644 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
647 static matrix4x4_t matrix_attenuationxyz =
650 {0.5, 0.0, 0.0, 0.5},
651 {0.0, 0.5, 0.0, 0.5},
652 {0.0, 0.0, 0.5, 0.5},
657 static matrix4x4_t matrix_attenuationz =
660 {0.0, 0.0, 0.5, 0.5},
661 {0.0, 0.0, 0.0, 0.5},
662 {0.0, 0.0, 0.0, 0.5},
667 int *R_Shadow_ResizeShadowElements(int numtris)
669 // make sure shadowelements is big enough for this volume
670 if (maxshadowelements < numtris * 24)
672 maxshadowelements = numtris * 24;
674 Mem_Free(shadowelements);
675 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
677 return shadowelements;
680 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
682 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
683 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
684 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
686 if (r_shadow_buffer_leafpvs)
687 Mem_Free(r_shadow_buffer_leafpvs);
688 if (r_shadow_buffer_leaflist)
689 Mem_Free(r_shadow_buffer_leaflist);
690 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
691 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
692 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
694 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
696 if (r_shadow_buffer_surfacepvs)
697 Mem_Free(r_shadow_buffer_surfacepvs);
698 if (r_shadow_buffer_surfacelist)
699 Mem_Free(r_shadow_buffer_surfacelist);
700 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
701 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
702 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
706 void R_Shadow_PrepareShadowMark(int numtris)
708 // make sure shadowmark is big enough for this volume
709 if (maxshadowmark < numtris)
711 maxshadowmark = numtris;
713 Mem_Free(shadowmark);
715 Mem_Free(shadowmarklist);
716 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
717 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
721 // if shadowmarkcount wrapped we clear the array and adjust accordingly
722 if (shadowmarkcount == 0)
725 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
730 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)
733 int outtriangles = 0, outvertices = 0;
737 if (maxvertexupdate < innumvertices)
739 maxvertexupdate = innumvertices;
741 Mem_Free(vertexupdate);
743 Mem_Free(vertexremap);
744 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
745 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
749 if (vertexupdatenum == 0)
752 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
753 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
756 for (i = 0;i < numshadowmarktris;i++)
757 shadowmark[shadowmarktris[i]] = shadowmarkcount;
759 for (i = 0;i < numshadowmarktris;i++)
761 element = inelement3i + shadowmarktris[i] * 3;
762 // make sure the vertices are created
763 for (j = 0;j < 3;j++)
765 if (vertexupdate[element[j]] != vertexupdatenum)
767 float ratio, direction[3];
768 vertexupdate[element[j]] = vertexupdatenum;
769 vertexremap[element[j]] = outvertices;
770 vertex = invertex3f + element[j] * 3;
771 // project one copy of the vertex to the sphere radius of the light
772 // (FIXME: would projecting it to the light box be better?)
773 VectorSubtract(vertex, projectorigin, direction);
774 ratio = projectdistance / VectorLength(direction);
775 VectorCopy(vertex, outvertex3f);
776 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
783 for (i = 0;i < numshadowmarktris;i++)
785 int remappedelement[3];
787 const int *neighbortriangle;
789 markindex = shadowmarktris[i] * 3;
790 element = inelement3i + markindex;
791 neighbortriangle = inneighbor3i + markindex;
792 // output the front and back triangles
793 outelement3i[0] = vertexremap[element[0]];
794 outelement3i[1] = vertexremap[element[1]];
795 outelement3i[2] = vertexremap[element[2]];
796 outelement3i[3] = vertexremap[element[2]] + 1;
797 outelement3i[4] = vertexremap[element[1]] + 1;
798 outelement3i[5] = vertexremap[element[0]] + 1;
802 // output the sides (facing outward from this triangle)
803 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
805 remappedelement[0] = vertexremap[element[0]];
806 remappedelement[1] = vertexremap[element[1]];
807 outelement3i[0] = remappedelement[1];
808 outelement3i[1] = remappedelement[0];
809 outelement3i[2] = remappedelement[0] + 1;
810 outelement3i[3] = remappedelement[1];
811 outelement3i[4] = remappedelement[0] + 1;
812 outelement3i[5] = remappedelement[1] + 1;
817 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
819 remappedelement[1] = vertexremap[element[1]];
820 remappedelement[2] = vertexremap[element[2]];
821 outelement3i[0] = remappedelement[2];
822 outelement3i[1] = remappedelement[1];
823 outelement3i[2] = remappedelement[1] + 1;
824 outelement3i[3] = remappedelement[2];
825 outelement3i[4] = remappedelement[1] + 1;
826 outelement3i[5] = remappedelement[2] + 1;
831 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
833 remappedelement[0] = vertexremap[element[0]];
834 remappedelement[2] = vertexremap[element[2]];
835 outelement3i[0] = remappedelement[0];
836 outelement3i[1] = remappedelement[2];
837 outelement3i[2] = remappedelement[2] + 1;
838 outelement3i[3] = remappedelement[0];
839 outelement3i[4] = remappedelement[2] + 1;
840 outelement3i[5] = remappedelement[0] + 1;
847 *outnumvertices = outvertices;
851 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)
854 if (projectdistance < 0.1)
856 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
859 if (!numverts || !nummarktris)
861 // make sure shadowelements is big enough for this volume
862 if (maxshadowelements < nummarktris * 24)
863 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
864 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
865 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
868 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)
873 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
875 tend = firsttriangle + numtris;
876 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
877 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
878 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
880 // surface box entirely inside light box, no box cull
881 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
882 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
883 shadowmarklist[numshadowmark++] = t;
887 // surface box not entirely inside light box, cull each triangle
888 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
890 v[0] = invertex3f + e[0] * 3;
891 v[1] = invertex3f + e[1] * 3;
892 v[2] = invertex3f + e[2] * 3;
893 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
894 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
895 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
896 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
897 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
898 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
899 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
900 shadowmarklist[numshadowmark++] = t;
905 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
908 if (r_shadow_compilingrtlight)
910 // if we're compiling an rtlight, capture the mesh
911 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
914 memset(&m, 0, sizeof(m));
915 m.pointer_vertex = vertex3f;
917 GL_LockArrays(0, numvertices);
918 if (r_shadowstage == SHADOWSTAGE_STENCIL)
920 // increment stencil if backface is behind depthbuffer
921 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
922 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
923 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
925 c_rt_shadowtris += numtriangles;
926 // decrement stencil if frontface is behind depthbuffer
927 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
928 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
930 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
932 c_rt_shadowtris += numtriangles;
936 static void R_Shadow_MakeTextures(void)
939 float v[3], intensity;
941 R_FreeTexturePool(&r_shadow_texturepool);
942 r_shadow_texturepool = R_AllocTexturePool();
943 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
944 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
945 #define ATTEN2DSIZE 64
946 #define ATTEN3DSIZE 32
947 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
948 for (y = 0;y < ATTEN2DSIZE;y++)
950 for (x = 0;x < ATTEN2DSIZE;x++)
952 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
953 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
955 intensity = 1.0f - sqrt(DotProduct(v, v));
957 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
958 d = bound(0, intensity, 255);
959 data[(y*ATTEN2DSIZE+x)*4+0] = d;
960 data[(y*ATTEN2DSIZE+x)*4+1] = d;
961 data[(y*ATTEN2DSIZE+x)*4+2] = d;
962 data[(y*ATTEN2DSIZE+x)*4+3] = d;
965 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
966 if (r_shadow_texture3d.integer)
968 for (z = 0;z < ATTEN3DSIZE;z++)
970 for (y = 0;y < ATTEN3DSIZE;y++)
972 for (x = 0;x < ATTEN3DSIZE;x++)
974 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
975 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
976 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
977 intensity = 1.0f - sqrt(DotProduct(v, v));
979 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
980 d = bound(0, intensity, 255);
981 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
982 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
983 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
984 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
988 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
993 void R_Shadow_ValidateCvars(void)
995 if (r_shadow_texture3d.integer && !gl_texture3d)
996 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
997 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
998 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1001 void R_Shadow_Stage_Begin(void)
1005 R_Shadow_ValidateCvars();
1007 if (!r_shadow_attenuation2dtexture
1008 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1009 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1010 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1011 R_Shadow_MakeTextures();
1013 memset(&m, 0, sizeof(m));
1014 GL_BlendFunc(GL_ONE, GL_ZERO);
1015 GL_DepthMask(false);
1018 GL_Color(0, 0, 0, 1);
1019 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1020 qglEnable(GL_CULL_FACE);
1021 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1022 r_shadowstage = SHADOWSTAGE_NONE;
1025 void R_Shadow_Stage_ShadowVolumes(void)
1028 memset(&m, 0, sizeof(m));
1030 GL_Color(1, 1, 1, 1);
1031 GL_ColorMask(0, 0, 0, 0);
1032 GL_BlendFunc(GL_ONE, GL_ZERO);
1033 GL_DepthMask(false);
1035 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1036 //if (r_shadow_shadow_polygonoffset.value != 0)
1038 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1039 // qglEnable(GL_POLYGON_OFFSET_FILL);
1042 // qglDisable(GL_POLYGON_OFFSET_FILL);
1043 qglDepthFunc(GL_LESS);
1044 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1045 qglEnable(GL_STENCIL_TEST);
1046 qglStencilFunc(GL_ALWAYS, 128, ~0);
1047 if (gl_ext_stenciltwoside.integer)
1049 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1050 qglDisable(GL_CULL_FACE);
1051 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1052 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1054 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1055 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1057 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1061 r_shadowstage = SHADOWSTAGE_STENCIL;
1062 qglEnable(GL_CULL_FACE);
1064 // this is changed by every shadow render so its value here is unimportant
1065 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1067 GL_Clear(GL_STENCIL_BUFFER_BIT);
1069 // LordHavoc note: many shadow volumes reside entirely inside the world
1070 // (that is to say they are entirely bounded by their lit surfaces),
1071 // which can be optimized by handling things as an inverted light volume,
1072 // with the shadow boundaries of the world being simulated by an altered
1073 // (129) bias to stencil clearing on such lights
1074 // FIXME: generate inverted light volumes for use as shadow volumes and
1075 // optimize for them as noted above
1078 void R_Shadow_Stage_Light(int shadowtest)
1081 memset(&m, 0, sizeof(m));
1083 GL_BlendFunc(GL_ONE, GL_ONE);
1084 GL_DepthMask(false);
1086 qglPolygonOffset(0, 0);
1087 //qglDisable(GL_POLYGON_OFFSET_FILL);
1088 GL_Color(1, 1, 1, 1);
1089 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1090 qglDepthFunc(GL_EQUAL);
1091 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1092 qglEnable(GL_CULL_FACE);
1094 qglEnable(GL_STENCIL_TEST);
1096 qglDisable(GL_STENCIL_TEST);
1097 if (gl_support_stenciltwoside)
1098 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1100 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1101 // only draw light where this geometry was already rendered AND the
1102 // stencil is 128 (values other than this mean shadow)
1103 qglStencilFunc(GL_EQUAL, 128, ~0);
1104 r_shadowstage = SHADOWSTAGE_LIGHT;
1108 void R_Shadow_Stage_End(void)
1111 memset(&m, 0, sizeof(m));
1113 GL_BlendFunc(GL_ONE, GL_ZERO);
1116 qglPolygonOffset(0, 0);
1117 //qglDisable(GL_POLYGON_OFFSET_FILL);
1118 GL_Color(1, 1, 1, 1);
1119 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1120 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1121 qglDepthFunc(GL_LEQUAL);
1122 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1123 qglDisable(GL_STENCIL_TEST);
1124 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1125 if (gl_support_stenciltwoside)
1126 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1128 qglStencilFunc(GL_ALWAYS, 128, ~0);
1129 r_shadowstage = SHADOWSTAGE_NONE;
1132 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1134 int i, ix1, iy1, ix2, iy2;
1135 float x1, y1, x2, y2, x, y, f;
1136 vec3_t smins, smaxs;
1138 if (!r_shadow_scissor.integer)
1140 // if view is inside the box, just say yes it's visible
1141 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1143 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1146 for (i = 0;i < 3;i++)
1148 if (r_viewforward[i] >= 0)
1159 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1160 if (DotProduct(r_viewforward, v2) <= f)
1162 // entirely behind nearclip plane
1165 if (DotProduct(r_viewforward, v) >= f)
1167 // entirely infront of nearclip plane
1168 x1 = y1 = x2 = y2 = 0;
1169 for (i = 0;i < 8;i++)
1171 v[0] = (i & 1) ? mins[0] : maxs[0];
1172 v[1] = (i & 2) ? mins[1] : maxs[1];
1173 v[2] = (i & 4) ? mins[2] : maxs[2];
1175 GL_TransformToScreen(v, v2);
1176 //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]);
1195 // clipped by nearclip plane
1196 // this is nasty and crude...
1197 // create viewspace bbox
1198 for (i = 0;i < 8;i++)
1200 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1201 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1202 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1203 v2[0] = -DotProduct(v, r_viewleft);
1204 v2[1] = DotProduct(v, r_viewup);
1205 v2[2] = DotProduct(v, r_viewforward);
1208 if (smins[0] > v2[0]) smins[0] = v2[0];
1209 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1210 if (smins[1] > v2[1]) smins[1] = v2[1];
1211 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1212 if (smins[2] > v2[2]) smins[2] = v2[2];
1213 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1217 smins[0] = smaxs[0] = v2[0];
1218 smins[1] = smaxs[1] = v2[1];
1219 smins[2] = smaxs[2] = v2[2];
1222 // now we have a bbox in viewspace
1223 // clip it to the view plane
1226 // return true if that culled the box
1227 if (smins[2] >= smaxs[2])
1229 // ok some of it is infront of the view, transform each corner back to
1230 // worldspace and then to screenspace and make screen rect
1231 // initialize these variables just to avoid compiler warnings
1232 x1 = y1 = x2 = y2 = 0;
1233 for (i = 0;i < 8;i++)
1235 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1236 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1237 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1238 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1239 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1240 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1242 GL_TransformToScreen(v, v2);
1243 //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]);
1260 // this code doesn't handle boxes with any points behind view properly
1261 x1 = 1000;x2 = -1000;
1262 y1 = 1000;y2 = -1000;
1263 for (i = 0;i < 8;i++)
1265 v[0] = (i & 1) ? mins[0] : maxs[0];
1266 v[1] = (i & 2) ? mins[1] : maxs[1];
1267 v[2] = (i & 4) ? mins[2] : maxs[2];
1269 GL_TransformToScreen(v, v2);
1270 //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]);
1288 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1289 if (ix1 < r_view_x) ix1 = r_view_x;
1290 if (iy1 < r_view_y) iy1 = r_view_y;
1291 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1292 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1293 if (ix2 <= ix1 || iy2 <= iy1)
1295 // set up the scissor rectangle
1296 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1297 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1298 //qglEnable(GL_SCISSOR_TEST);
1303 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1305 float *color4f = varray_color4f;
1306 float dist, dot, intensity, v[3], n[3];
1307 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1309 Matrix4x4_Transform(m, vertex3f, v);
1310 if ((dist = DotProduct(v, v)) < 1)
1312 Matrix4x4_Transform3x3(m, normal3f, n);
1313 if ((dot = DotProduct(n, v)) > 0)
1316 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1317 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1318 VectorScale(lightcolor, intensity, color4f);
1323 VectorClear(color4f);
1329 VectorClear(color4f);
1335 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1337 float *color4f = varray_color4f;
1338 float dist, dot, intensity, v[3], n[3];
1339 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1341 Matrix4x4_Transform(m, vertex3f, v);
1342 if ((dist = fabs(v[2])) < 1)
1344 Matrix4x4_Transform3x3(m, normal3f, n);
1345 if ((dot = DotProduct(n, v)) > 0)
1347 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1348 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1349 VectorScale(lightcolor, intensity, color4f);
1354 VectorClear(color4f);
1360 VectorClear(color4f);
1366 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1368 float *color4f = varray_color4f;
1369 float dot, intensity, v[3], n[3];
1370 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1372 Matrix4x4_Transform(m, vertex3f, v);
1373 Matrix4x4_Transform3x3(m, normal3f, n);
1374 if ((dot = DotProduct(n, v)) > 0)
1376 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1377 VectorScale(lightcolor, intensity, color4f);
1382 VectorClear(color4f);
1388 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1390 float *color4f = varray_color4f;
1391 float dist, intensity, v[3];
1392 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1394 Matrix4x4_Transform(m, vertex3f, v);
1395 if ((dist = DotProduct(v, v)) < 1)
1398 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1399 VectorScale(lightcolor, intensity, color4f);
1404 VectorClear(color4f);
1410 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1412 float *color4f = varray_color4f;
1413 float dist, intensity, v[3];
1414 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1416 Matrix4x4_Transform(m, vertex3f, v);
1417 if ((dist = fabs(v[2])) < 1)
1419 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1420 VectorScale(lightcolor, intensity, color4f);
1425 VectorClear(color4f);
1431 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1432 #define USETEXMATRIX
1434 #ifndef USETEXMATRIX
1435 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1436 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1437 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1441 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1442 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1443 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1450 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1454 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1455 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1463 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)
1467 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1469 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1470 // the cubemap normalizes this for us
1471 out3f[0] = DotProduct(svector3f, lightdir);
1472 out3f[1] = DotProduct(tvector3f, lightdir);
1473 out3f[2] = DotProduct(normal3f, lightdir);
1477 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)
1480 float lightdir[3], eyedir[3], halfdir[3];
1481 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1483 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1484 VectorNormalizeFast(lightdir);
1485 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1486 VectorNormalizeFast(eyedir);
1487 VectorAdd(lightdir, eyedir, halfdir);
1488 // the cubemap normalizes this for us
1489 out3f[0] = DotProduct(svector3f, halfdir);
1490 out3f[1] = DotProduct(tvector3f, halfdir);
1491 out3f[2] = DotProduct(normal3f, halfdir);
1495 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 *relativelightorigin, const float *relativeeyeorigin, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int visiblelighting)
1498 float color[3], color2[3], colorscale;
1501 basetexture = r_texture_white;
1503 bumptexture = r_texture_blanknormalmap;
1504 if (!lightcolorbase)
1505 lightcolorbase = vec3_origin;
1506 if (!lightcolorpants)
1507 lightcolorpants = vec3_origin;
1508 if (!lightcolorshirt)
1509 lightcolorshirt = vec3_origin;
1510 specularscale *= r_shadow_glossintensity.value;
1513 if (r_shadow_gloss.integer >= 2)
1515 glosstexture = r_texture_white;
1516 specularscale *= r_shadow_gloss2intensity.value;
1520 glosstexture = r_texture_black;
1524 if (r_shadow_gloss.integer < 1)
1527 lightcubemap = r_texture_whitecube;
1528 if ((ambientscale + diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1530 if (visiblelighting)
1533 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1534 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1535 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1537 // TODO: add direct pants/shirt rendering
1538 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1539 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1540 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1541 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1543 bumptexture = r_texture_blanknormalmap;
1545 glosstexture = r_texture_white;
1548 colorscale = ambientscale;
1549 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1552 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1555 else if (r_textureunits.integer >= 4 && lightcubemap)
1558 else if (r_textureunits.integer >= 3 && !lightcubemap)
1563 VectorScale(lightcolorbase, colorscale, color2);
1564 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1569 colorscale = diffusescale;
1570 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1572 // 3/2 3D combine path (Geforce3, Radeon 8500)
1575 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1577 // 1/2/2 3D combine path (original Radeon)
1580 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1582 // 2/2 3D combine path (original Radeon)
1585 else if (r_textureunits.integer >= 4)
1587 // 4/2 2D combine path (Geforce3, Radeon 8500)
1592 // 2/2/2 2D combine path (any dot3 card)
1595 VectorScale(lightcolorbase, colorscale, color2);
1596 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1599 if (specularscale && glosstexture != r_texture_black)
1601 //if (gl_support_blendsquare)
1603 colorscale = specularscale;
1604 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1606 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1610 VectorScale(lightcolorbase, colorscale, color2);
1611 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1618 // TODO: add direct pants/shirt rendering
1619 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1620 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1621 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1622 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1625 VectorScale(lightcolorbase, ambientscale, color2);
1626 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1631 VectorScale(lightcolorbase, diffusescale, color2);
1632 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1638 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1639 memset(&m, 0, sizeof(m));
1640 m.pointer_vertex = vertex3f;
1642 GL_LockArrays(firstvertex, numvertices);
1643 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1644 GL_LockArrays(0, 0);
1648 // FIXME: support EF_NODEPTHTEST
1649 GL_DepthMask(false);
1651 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1653 unsigned int perm, prog;
1654 // GLSL shader path (GFFX5200, Radeon 9500)
1655 memset(&m, 0, sizeof(m));
1656 m.pointer_vertex = vertex3f;
1657 m.pointer_texcoord[0] = texcoord2f;
1658 m.pointer_texcoord3f[1] = svector3f;
1659 m.pointer_texcoord3f[2] = tvector3f;
1660 m.pointer_texcoord3f[3] = normal3f;
1661 m.tex[0] = R_GetTexture(bumptexture);
1662 m.tex[1] = R_GetTexture(basetexture);
1663 m.tex[2] = R_GetTexture(glosstexture);
1664 m.texcubemap[3] = R_GetTexture(lightcubemap);
1665 // TODO: support fog (after renderer is converted to texture fog)
1666 m.tex[4] = R_GetTexture(r_texture_white);
1667 m.texmatrix[3] = *matrix_modeltolight;
1669 GL_BlendFunc(GL_ONE, GL_ONE);
1670 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1673 // only add a feature to the permutation if that permutation exists
1674 // (otherwise it might end up not using a shader at all, which looks
1675 // worse than using less features)
1676 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1677 perm |= SHADERPERMUTATION_SPECULAR;
1678 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1679 // perm |= SHADERPERMUTATION_FOG;
1680 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1681 perm |= SHADERPERMUTATION_CUBEFILTER;
1682 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1683 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1684 prog = r_shadow_program_light[perm];
1685 qglUseProgramObjectARB(prog);CHECKGLERROR
1686 // TODO: support fog (after renderer is converted to texture fog)
1687 if (perm & SHADERPERMUTATION_FOG)
1689 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1691 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1692 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1693 if (perm & SHADERPERMUTATION_SPECULAR)
1695 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1696 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1698 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1699 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1700 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1702 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1704 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1706 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1707 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1710 GL_LockArrays(firstvertex, numvertices);
1711 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1713 c_rt_lighttris += numtriangles;
1714 // TODO: add direct pants/shirt rendering
1715 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1717 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1718 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1719 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1721 c_rt_lighttris += numtriangles;
1723 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1725 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1726 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1727 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1729 c_rt_lighttris += numtriangles;
1731 GL_LockArrays(0, 0);
1732 qglUseProgramObjectARB(0);
1733 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1734 qglBegin(GL_TRIANGLES);
1738 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1740 // TODO: add direct pants/shirt rendering
1741 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1742 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1743 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1744 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1746 bumptexture = r_texture_blanknormalmap;
1748 glosstexture = r_texture_white;
1752 colorscale = ambientscale;
1753 // colorscale accounts for how much we multiply the brightness
1756 // mult is how many times the final pass of the lighting will be
1757 // performed to get more brightness than otherwise possible.
1759 // Limit mult to 64 for sanity sake.
1760 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1762 // 3 3D combine path (Geforce3, Radeon 8500)
1763 memset(&m, 0, sizeof(m));
1764 m.pointer_vertex = vertex3f;
1765 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1767 m.pointer_texcoord3f[0] = vertex3f;
1768 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1770 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1771 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1773 m.tex[1] = R_GetTexture(basetexture);
1774 m.pointer_texcoord[1] = texcoord2f;
1775 m.texcubemap[2] = R_GetTexture(lightcubemap);
1777 m.pointer_texcoord3f[2] = vertex3f;
1778 m.texmatrix[2] = *matrix_modeltolight;
1780 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1781 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1783 GL_BlendFunc(GL_ONE, GL_ONE);
1785 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1787 // 2 3D combine path (Geforce3, original Radeon)
1788 memset(&m, 0, sizeof(m));
1789 m.pointer_vertex = vertex3f;
1790 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1792 m.pointer_texcoord3f[0] = vertex3f;
1793 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1795 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1796 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1798 m.tex[1] = R_GetTexture(basetexture);
1799 m.pointer_texcoord[1] = texcoord2f;
1800 GL_BlendFunc(GL_ONE, GL_ONE);
1802 else if (r_textureunits.integer >= 4 && lightcubemap)
1804 // 4 2D combine path (Geforce3, Radeon 8500)
1805 memset(&m, 0, sizeof(m));
1806 m.pointer_vertex = vertex3f;
1807 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1809 m.pointer_texcoord3f[0] = vertex3f;
1810 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1812 m.pointer_texcoord[0] = varray_texcoord2f[0];
1813 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1815 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1817 m.pointer_texcoord3f[1] = vertex3f;
1818 m.texmatrix[1] = *matrix_modeltoattenuationz;
1820 m.pointer_texcoord[1] = varray_texcoord2f[1];
1821 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1823 m.tex[2] = R_GetTexture(basetexture);
1824 m.pointer_texcoord[2] = texcoord2f;
1827 m.texcubemap[3] = R_GetTexture(lightcubemap);
1829 m.pointer_texcoord3f[3] = vertex3f;
1830 m.texmatrix[3] = *matrix_modeltolight;
1832 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1833 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1836 GL_BlendFunc(GL_ONE, GL_ONE);
1838 else if (r_textureunits.integer >= 3 && !lightcubemap)
1840 // 3 2D combine path (Geforce3, original Radeon)
1841 memset(&m, 0, sizeof(m));
1842 m.pointer_vertex = vertex3f;
1843 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1845 m.pointer_texcoord3f[0] = vertex3f;
1846 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1848 m.pointer_texcoord[0] = varray_texcoord2f[0];
1849 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1851 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1853 m.pointer_texcoord3f[1] = vertex3f;
1854 m.texmatrix[1] = *matrix_modeltoattenuationz;
1856 m.pointer_texcoord[1] = varray_texcoord2f[1];
1857 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1859 m.tex[2] = R_GetTexture(basetexture);
1860 m.pointer_texcoord[2] = texcoord2f;
1861 GL_BlendFunc(GL_ONE, GL_ONE);
1865 // 2/2/2 2D combine path (any dot3 card)
1866 memset(&m, 0, sizeof(m));
1867 m.pointer_vertex = vertex3f;
1868 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1870 m.pointer_texcoord3f[0] = vertex3f;
1871 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1873 m.pointer_texcoord[0] = varray_texcoord2f[0];
1874 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1876 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1878 m.pointer_texcoord3f[1] = vertex3f;
1879 m.texmatrix[1] = *matrix_modeltoattenuationz;
1881 m.pointer_texcoord[1] = varray_texcoord2f[1];
1882 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1885 GL_ColorMask(0,0,0,1);
1886 GL_BlendFunc(GL_ONE, GL_ZERO);
1887 GL_LockArrays(firstvertex, numvertices);
1888 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1889 GL_LockArrays(0, 0);
1891 c_rt_lighttris += numtriangles;
1893 memset(&m, 0, sizeof(m));
1894 m.pointer_vertex = vertex3f;
1895 m.tex[0] = R_GetTexture(basetexture);
1896 m.pointer_texcoord[0] = texcoord2f;
1899 m.texcubemap[1] = R_GetTexture(lightcubemap);
1901 m.pointer_texcoord3f[1] = vertex3f;
1902 m.texmatrix[1] = *matrix_modeltolight;
1904 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1905 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1908 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1910 // this final code is shared
1912 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1913 VectorScale(lightcolorbase, colorscale, color2);
1914 GL_LockArrays(firstvertex, numvertices);
1915 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1917 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1918 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1920 c_rt_lighttris += numtriangles;
1922 GL_LockArrays(0, 0);
1927 colorscale = diffusescale;
1928 // colorscale accounts for how much we multiply the brightness
1931 // mult is how many times the final pass of the lighting will be
1932 // performed to get more brightness than otherwise possible.
1934 // Limit mult to 64 for sanity sake.
1935 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1937 // 3/2 3D combine path (Geforce3, Radeon 8500)
1938 memset(&m, 0, sizeof(m));
1939 m.pointer_vertex = vertex3f;
1940 m.tex[0] = R_GetTexture(bumptexture);
1941 m.texcombinergb[0] = GL_REPLACE;
1942 m.pointer_texcoord[0] = texcoord2f;
1943 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1944 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1945 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1946 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1947 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1949 m.pointer_texcoord3f[2] = vertex3f;
1950 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1952 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1953 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1956 GL_ColorMask(0,0,0,1);
1957 GL_BlendFunc(GL_ONE, GL_ZERO);
1958 GL_LockArrays(firstvertex, numvertices);
1959 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1960 GL_LockArrays(0, 0);
1962 c_rt_lighttris += numtriangles;
1964 memset(&m, 0, sizeof(m));
1965 m.pointer_vertex = vertex3f;
1966 m.tex[0] = R_GetTexture(basetexture);
1967 m.pointer_texcoord[0] = texcoord2f;
1970 m.texcubemap[1] = R_GetTexture(lightcubemap);
1972 m.pointer_texcoord3f[1] = vertex3f;
1973 m.texmatrix[1] = *matrix_modeltolight;
1975 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1976 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1979 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1981 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1983 // 1/2/2 3D combine path (original Radeon)
1984 memset(&m, 0, sizeof(m));
1985 m.pointer_vertex = vertex3f;
1986 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1988 m.pointer_texcoord3f[0] = vertex3f;
1989 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1991 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1992 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1995 GL_ColorMask(0,0,0,1);
1996 GL_BlendFunc(GL_ONE, GL_ZERO);
1997 GL_LockArrays(firstvertex, numvertices);
1998 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1999 GL_LockArrays(0, 0);
2001 c_rt_lighttris += numtriangles;
2003 memset(&m, 0, sizeof(m));
2004 m.pointer_vertex = vertex3f;
2005 m.tex[0] = R_GetTexture(bumptexture);
2006 m.texcombinergb[0] = GL_REPLACE;
2007 m.pointer_texcoord[0] = texcoord2f;
2008 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2009 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2010 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2011 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2013 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2014 GL_LockArrays(firstvertex, numvertices);
2015 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2016 GL_LockArrays(0, 0);
2018 c_rt_lighttris += numtriangles;
2020 memset(&m, 0, sizeof(m));
2021 m.pointer_vertex = vertex3f;
2022 m.tex[0] = R_GetTexture(basetexture);
2023 m.pointer_texcoord[0] = texcoord2f;
2026 m.texcubemap[1] = R_GetTexture(lightcubemap);
2028 m.pointer_texcoord3f[1] = vertex3f;
2029 m.texmatrix[1] = *matrix_modeltolight;
2031 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2032 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2035 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2037 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
2039 // 2/2 3D combine path (original Radeon)
2040 memset(&m, 0, sizeof(m));
2041 m.pointer_vertex = vertex3f;
2042 m.tex[0] = R_GetTexture(bumptexture);
2043 m.texcombinergb[0] = GL_REPLACE;
2044 m.pointer_texcoord[0] = texcoord2f;
2045 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2046 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2047 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2048 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2050 GL_ColorMask(0,0,0,1);
2051 GL_BlendFunc(GL_ONE, GL_ZERO);
2052 GL_LockArrays(firstvertex, numvertices);
2053 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2054 GL_LockArrays(0, 0);
2056 c_rt_lighttris += numtriangles;
2058 memset(&m, 0, sizeof(m));
2059 m.pointer_vertex = vertex3f;
2060 m.tex[0] = R_GetTexture(basetexture);
2061 m.pointer_texcoord[0] = texcoord2f;
2062 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2064 m.pointer_texcoord3f[1] = vertex3f;
2065 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2067 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2068 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2070 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2072 else if (r_textureunits.integer >= 4)
2074 // 4/2 2D combine path (Geforce3, Radeon 8500)
2075 memset(&m, 0, sizeof(m));
2076 m.pointer_vertex = vertex3f;
2077 m.tex[0] = R_GetTexture(bumptexture);
2078 m.texcombinergb[0] = GL_REPLACE;
2079 m.pointer_texcoord[0] = texcoord2f;
2080 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2081 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2082 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2083 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2084 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2086 m.pointer_texcoord3f[2] = vertex3f;
2087 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2089 m.pointer_texcoord[2] = varray_texcoord2f[2];
2090 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2092 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2094 m.pointer_texcoord3f[3] = vertex3f;
2095 m.texmatrix[3] = *matrix_modeltoattenuationz;
2097 m.pointer_texcoord[3] = varray_texcoord2f[3];
2098 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2101 GL_ColorMask(0,0,0,1);
2102 GL_BlendFunc(GL_ONE, GL_ZERO);
2103 GL_LockArrays(firstvertex, numvertices);
2104 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2105 GL_LockArrays(0, 0);
2107 c_rt_lighttris += numtriangles;
2109 memset(&m, 0, sizeof(m));
2110 m.pointer_vertex = vertex3f;
2111 m.tex[0] = R_GetTexture(basetexture);
2112 m.pointer_texcoord[0] = texcoord2f;
2115 m.texcubemap[1] = R_GetTexture(lightcubemap);
2117 m.pointer_texcoord3f[1] = vertex3f;
2118 m.texmatrix[1] = *matrix_modeltolight;
2120 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2121 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2124 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2128 // 2/2/2 2D combine path (any dot3 card)
2129 memset(&m, 0, sizeof(m));
2130 m.pointer_vertex = vertex3f;
2131 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2133 m.pointer_texcoord3f[0] = vertex3f;
2134 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2136 m.pointer_texcoord[0] = varray_texcoord2f[0];
2137 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2139 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2141 m.pointer_texcoord3f[1] = vertex3f;
2142 m.texmatrix[1] = *matrix_modeltoattenuationz;
2144 m.pointer_texcoord[1] = varray_texcoord2f[1];
2145 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2148 GL_ColorMask(0,0,0,1);
2149 GL_BlendFunc(GL_ONE, GL_ZERO);
2150 GL_LockArrays(firstvertex, numvertices);
2151 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2152 GL_LockArrays(0, 0);
2154 c_rt_lighttris += numtriangles;
2156 memset(&m, 0, sizeof(m));
2157 m.pointer_vertex = vertex3f;
2158 m.tex[0] = R_GetTexture(bumptexture);
2159 m.texcombinergb[0] = GL_REPLACE;
2160 m.pointer_texcoord[0] = texcoord2f;
2161 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2162 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2163 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2164 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2166 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2167 GL_LockArrays(firstvertex, numvertices);
2168 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2169 GL_LockArrays(0, 0);
2171 c_rt_lighttris += numtriangles;
2173 memset(&m, 0, sizeof(m));
2174 m.pointer_vertex = vertex3f;
2175 m.tex[0] = R_GetTexture(basetexture);
2176 m.pointer_texcoord[0] = texcoord2f;
2179 m.texcubemap[1] = R_GetTexture(lightcubemap);
2181 m.pointer_texcoord3f[1] = vertex3f;
2182 m.texmatrix[1] = *matrix_modeltolight;
2184 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2185 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2188 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2190 // this final code is shared
2192 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2193 VectorScale(lightcolorbase, colorscale, color2);
2194 GL_LockArrays(firstvertex, numvertices);
2195 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2197 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2198 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2200 c_rt_lighttris += numtriangles;
2202 GL_LockArrays(0, 0);
2204 if (specularscale && glosstexture != r_texture_black)
2206 // FIXME: detect blendsquare!
2207 //if (gl_support_blendsquare)
2209 colorscale = specularscale;
2211 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2213 // 2/0/0/1/2 3D combine blendsquare path
2214 memset(&m, 0, sizeof(m));
2215 m.pointer_vertex = vertex3f;
2216 m.tex[0] = R_GetTexture(bumptexture);
2217 m.pointer_texcoord[0] = texcoord2f;
2218 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2219 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2220 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2221 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2223 GL_ColorMask(0,0,0,1);
2224 // this squares the result
2225 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2226 GL_LockArrays(firstvertex, numvertices);
2227 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2228 GL_LockArrays(0, 0);
2230 c_rt_lighttris += numtriangles;
2232 memset(&m, 0, sizeof(m));
2233 m.pointer_vertex = vertex3f;
2235 GL_LockArrays(firstvertex, numvertices);
2236 // square alpha in framebuffer a few times to make it shiny
2237 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2238 // these comments are a test run through this math for intensity 0.5
2239 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2240 // 0.25 * 0.25 = 0.0625 (this is another pass)
2241 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2242 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2244 c_rt_lighttris += numtriangles;
2245 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2247 c_rt_lighttris += numtriangles;
2248 GL_LockArrays(0, 0);
2250 memset(&m, 0, sizeof(m));
2251 m.pointer_vertex = vertex3f;
2252 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2254 m.pointer_texcoord3f[0] = vertex3f;
2255 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2257 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2258 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2261 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2262 GL_LockArrays(firstvertex, numvertices);
2263 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2264 GL_LockArrays(0, 0);
2266 c_rt_lighttris += numtriangles;
2268 memset(&m, 0, sizeof(m));
2269 m.pointer_vertex = vertex3f;
2270 m.tex[0] = R_GetTexture(glosstexture);
2271 m.pointer_texcoord[0] = texcoord2f;
2274 m.texcubemap[1] = R_GetTexture(lightcubemap);
2276 m.pointer_texcoord3f[1] = vertex3f;
2277 m.texmatrix[1] = *matrix_modeltolight;
2279 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2280 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2283 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2285 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2287 // 2/0/0/2 3D combine blendsquare path
2288 memset(&m, 0, sizeof(m));
2289 m.pointer_vertex = vertex3f;
2290 m.tex[0] = R_GetTexture(bumptexture);
2291 m.pointer_texcoord[0] = texcoord2f;
2292 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2293 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2294 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2295 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2297 GL_ColorMask(0,0,0,1);
2298 // this squares the result
2299 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2300 GL_LockArrays(firstvertex, numvertices);
2301 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2302 GL_LockArrays(0, 0);
2304 c_rt_lighttris += numtriangles;
2306 memset(&m, 0, sizeof(m));
2307 m.pointer_vertex = vertex3f;
2309 GL_LockArrays(firstvertex, numvertices);
2310 // square alpha in framebuffer a few times to make it shiny
2311 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2312 // these comments are a test run through this math for intensity 0.5
2313 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2314 // 0.25 * 0.25 = 0.0625 (this is another pass)
2315 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2316 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2318 c_rt_lighttris += numtriangles;
2319 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2321 c_rt_lighttris += numtriangles;
2322 GL_LockArrays(0, 0);
2324 memset(&m, 0, sizeof(m));
2325 m.pointer_vertex = vertex3f;
2326 m.tex[0] = R_GetTexture(glosstexture);
2327 m.pointer_texcoord[0] = texcoord2f;
2328 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2330 m.pointer_texcoord3f[1] = vertex3f;
2331 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2333 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2334 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2336 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2340 // 2/0/0/2/2 2D combine blendsquare path
2341 memset(&m, 0, sizeof(m));
2342 m.pointer_vertex = vertex3f;
2343 m.tex[0] = R_GetTexture(bumptexture);
2344 m.pointer_texcoord[0] = texcoord2f;
2345 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2346 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2347 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2348 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2350 GL_ColorMask(0,0,0,1);
2351 // this squares the result
2352 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2353 GL_LockArrays(firstvertex, numvertices);
2354 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2355 GL_LockArrays(0, 0);
2357 c_rt_lighttris += numtriangles;
2359 memset(&m, 0, sizeof(m));
2360 m.pointer_vertex = vertex3f;
2362 GL_LockArrays(firstvertex, numvertices);
2363 // square alpha in framebuffer a few times to make it shiny
2364 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2365 // these comments are a test run through this math for intensity 0.5
2366 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2367 // 0.25 * 0.25 = 0.0625 (this is another pass)
2368 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2369 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2371 c_rt_lighttris += numtriangles;
2372 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2374 c_rt_lighttris += numtriangles;
2375 GL_LockArrays(0, 0);
2377 memset(&m, 0, sizeof(m));
2378 m.pointer_vertex = vertex3f;
2379 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2381 m.pointer_texcoord3f[0] = vertex3f;
2382 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2384 m.pointer_texcoord[0] = varray_texcoord2f[0];
2385 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2387 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2389 m.pointer_texcoord3f[1] = vertex3f;
2390 m.texmatrix[1] = *matrix_modeltoattenuationz;
2392 m.pointer_texcoord[1] = varray_texcoord2f[1];
2393 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2396 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2397 GL_LockArrays(firstvertex, numvertices);
2398 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2399 GL_LockArrays(0, 0);
2401 c_rt_lighttris += numtriangles;
2403 memset(&m, 0, sizeof(m));
2404 m.pointer_vertex = vertex3f;
2405 m.tex[0] = R_GetTexture(glosstexture);
2406 m.pointer_texcoord[0] = texcoord2f;
2409 m.texcubemap[1] = R_GetTexture(lightcubemap);
2411 m.pointer_texcoord3f[1] = vertex3f;
2412 m.texmatrix[1] = *matrix_modeltolight;
2414 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2415 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2418 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2421 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2422 VectorScale(lightcolorbase, colorscale, color2);
2423 GL_LockArrays(firstvertex, numvertices);
2424 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2426 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2427 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2429 c_rt_lighttris += numtriangles;
2431 GL_LockArrays(0, 0);
2437 // TODO: add direct pants/shirt rendering
2438 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2439 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
2440 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2441 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
2444 GL_BlendFunc(GL_ONE, GL_ONE);
2445 VectorScale(lightcolorbase, ambientscale, color2);
2446 memset(&m, 0, sizeof(m));
2447 m.pointer_vertex = vertex3f;
2448 m.tex[0] = R_GetTexture(basetexture);
2449 m.pointer_texcoord[0] = texcoord2f;
2450 if (r_textureunits.integer >= 2)
2453 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2455 m.pointer_texcoord3f[1] = vertex3f;
2456 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2458 m.pointer_texcoord[1] = varray_texcoord2f[1];
2459 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2461 if (r_textureunits.integer >= 3)
2463 // Geforce3/Radeon class but not using dot3
2464 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2466 m.pointer_texcoord3f[2] = vertex3f;
2467 m.texmatrix[2] = *matrix_modeltoattenuationz;
2469 m.pointer_texcoord[2] = varray_texcoord2f[2];
2470 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2474 if (r_textureunits.integer >= 3)
2475 m.pointer_color = NULL;
2477 m.pointer_color = varray_color4f;
2479 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2481 color[0] = bound(0, color2[0], 1);
2482 color[1] = bound(0, color2[1], 1);
2483 color[2] = bound(0, color2[2], 1);
2484 if (r_textureunits.integer >= 3)
2485 GL_Color(color[0], color[1], color[2], 1);
2486 else if (r_textureunits.integer >= 2)
2487 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2489 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2490 GL_LockArrays(firstvertex, numvertices);
2491 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2492 GL_LockArrays(0, 0);
2494 c_rt_lighttris += numtriangles;
2499 GL_BlendFunc(GL_ONE, GL_ONE);
2500 VectorScale(lightcolorbase, diffusescale, color2);
2501 memset(&m, 0, sizeof(m));
2502 m.pointer_vertex = vertex3f;
2503 m.pointer_color = varray_color4f;
2504 m.tex[0] = R_GetTexture(basetexture);
2505 m.pointer_texcoord[0] = texcoord2f;
2506 if (r_textureunits.integer >= 2)
2509 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2511 m.pointer_texcoord3f[1] = vertex3f;
2512 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2514 m.pointer_texcoord[1] = varray_texcoord2f[1];
2515 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2517 if (r_textureunits.integer >= 3)
2519 // Geforce3/Radeon class but not using dot3
2520 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2522 m.pointer_texcoord3f[2] = vertex3f;
2523 m.texmatrix[2] = *matrix_modeltoattenuationz;
2525 m.pointer_texcoord[2] = varray_texcoord2f[2];
2526 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2531 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2533 color[0] = bound(0, color2[0], 1);
2534 color[1] = bound(0, color2[1], 1);
2535 color[2] = bound(0, color2[2], 1);
2536 if (r_textureunits.integer >= 3)
2537 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2538 else if (r_textureunits.integer >= 2)
2539 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2541 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2542 GL_LockArrays(firstvertex, numvertices);
2543 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2544 GL_LockArrays(0, 0);
2546 c_rt_lighttris += numtriangles;
2552 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2556 R_RTLight_Uncompile(rtlight);
2557 memset(rtlight, 0, sizeof(*rtlight));
2559 VectorCopy(light->origin, rtlight->shadoworigin);
2560 VectorCopy(light->color, rtlight->color);
2561 rtlight->radius = light->radius;
2562 //rtlight->cullradius = rtlight->radius;
2563 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2564 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2565 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2566 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2567 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2568 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2569 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2570 rtlight->cubemapname[0] = 0;
2571 if (light->cubemapname[0])
2572 strcpy(rtlight->cubemapname, light->cubemapname);
2573 else if (light->cubemapnum > 0)
2574 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2575 rtlight->shadow = light->shadow;
2576 rtlight->corona = light->corona;
2577 rtlight->style = light->style;
2578 rtlight->isstatic = isstatic;
2579 rtlight->coronasizescale = light->coronasizescale;
2580 rtlight->ambientscale = light->ambientscale;
2581 rtlight->diffusescale = light->diffusescale;
2582 rtlight->specularscale = light->specularscale;
2583 rtlight->flags = light->flags;
2584 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2585 // ConcatScale won't work here because this needs to scale rotate and
2586 // translate, not just rotate
2587 scale = 1.0f / rtlight->radius;
2588 for (k = 0;k < 3;k++)
2589 for (j = 0;j < 4;j++)
2590 rtlight->matrix_worldtolight.m[k][j] *= scale;
2591 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2592 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2594 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2595 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2596 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2597 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2600 // compiles rtlight geometry
2601 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2602 void R_RTLight_Compile(rtlight_t *rtlight)
2604 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2605 entity_render_t *ent = r_refdef.worldentity;
2606 model_t *model = r_refdef.worldmodel;
2609 // compile the light
2610 rtlight->compiled = true;
2611 rtlight->static_numleafs = 0;
2612 rtlight->static_numleafpvsbytes = 0;
2613 rtlight->static_leaflist = NULL;
2614 rtlight->static_leafpvs = NULL;
2615 rtlight->static_numsurfaces = 0;
2616 rtlight->static_surfacelist = NULL;
2617 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2618 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2619 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2620 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2621 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2622 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2624 if (model && model->GetLightInfo)
2626 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2627 r_shadow_compilingrtlight = rtlight;
2628 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->brush.num_surfaces);
2629 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);
2630 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2631 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2632 rtlight->static_numleafs = numleafs;
2633 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2634 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2635 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2636 rtlight->static_numsurfaces = numsurfaces;
2637 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2639 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2640 if (numleafpvsbytes)
2641 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2643 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2644 if (model->DrawShadowVolume && rtlight->shadow)
2646 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2647 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2648 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2650 if (model->DrawLight)
2652 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2653 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, 0, 0, 0, numsurfaces, r_shadow_buffer_surfacelist, 0);
2654 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2656 // switch back to rendering when DrawShadowVolume or DrawLight is called
2657 r_shadow_compilingrtlight = NULL;
2661 // use smallest available cullradius - box radius or light radius
2662 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2663 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2667 if (rtlight->static_meshchain_shadow)
2670 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2673 shadowtris += mesh->numtriangles;
2679 if (rtlight->static_meshchain_light)
2682 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2685 lighttris += mesh->numtriangles;
2689 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);
2692 void R_RTLight_Uncompile(rtlight_t *rtlight)
2694 if (rtlight->compiled)
2696 if (rtlight->static_meshchain_shadow)
2697 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2698 rtlight->static_meshchain_shadow = NULL;
2699 if (rtlight->static_meshchain_light)
2700 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2701 rtlight->static_meshchain_light = NULL;
2702 // these allocations are grouped
2703 if (rtlight->static_leaflist)
2704 Mem_Free(rtlight->static_leaflist);
2705 rtlight->static_numleafs = 0;
2706 rtlight->static_numleafpvsbytes = 0;
2707 rtlight->static_leaflist = NULL;
2708 rtlight->static_leafpvs = NULL;
2709 rtlight->static_numsurfaces = 0;
2710 rtlight->static_surfacelist = NULL;
2711 rtlight->compiled = false;
2715 void R_Shadow_UncompileWorldLights(void)
2718 for (light = r_shadow_worldlightchain;light;light = light->next)
2719 R_RTLight_Uncompile(&light->rtlight);
2722 void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
2724 int i, shadow, usestencil;
2725 entity_render_t *ent;
2727 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2728 rtexture_t *cubemaptexture;
2729 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2730 int numleafs, numsurfaces;
2731 int *leaflist, *surfacelist;
2733 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2737 // skip lights that don't light (corona only lights)
2738 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2741 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2742 VectorScale(rtlight->color, f, lightcolor);
2743 if (VectorLength2(lightcolor) < 0.01)
2746 if (rtlight->selected)
2748 f = 2 + sin(realtime * M_PI * 4.0);
2749 VectorScale(lightcolor, f, lightcolor);
2753 // loading is done before visibility checks because loading should happen
2754 // all at once at the start of a level, not when it stalls gameplay.
2755 // (especially important to benchmarks)
2756 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2757 R_RTLight_Compile(rtlight);
2758 if (rtlight->cubemapname[0])
2759 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2761 cubemaptexture = NULL;
2763 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2764 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2765 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2766 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2767 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2768 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2769 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2776 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2778 // compiled light, world available and can receive realtime lighting
2779 // retrieve leaf information
2780 numleafs = rtlight->static_numleafs;
2781 leaflist = rtlight->static_leaflist;
2782 leafpvs = rtlight->static_leafpvs;
2783 numsurfaces = rtlight->static_numsurfaces;
2784 surfacelist = rtlight->static_surfacelist;
2785 VectorCopy(rtlight->cullmins, cullmins);
2786 VectorCopy(rtlight->cullmaxs, cullmaxs);
2788 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2790 // dynamic light, world available and can receive realtime lighting
2791 // if the light box is offscreen, skip it right away
2792 if (R_CullBox(cullmins, cullmaxs))
2794 // calculate lit surfaces and leafs
2795 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
2796 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2797 leaflist = r_shadow_buffer_leaflist;
2798 leafpvs = r_shadow_buffer_leafpvs;
2799 surfacelist = r_shadow_buffer_surfacelist;
2801 // if the reduced leaf bounds are offscreen, skip it
2802 if (R_CullBox(cullmins, cullmaxs))
2804 // check if light is illuminating any visible leafs
2807 for (i = 0;i < numleafs;i++)
2808 if (r_worldleafvisible[leaflist[i]])
2813 // set up a scissor rectangle for this light
2814 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2817 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2820 if (shadow && ((gl_stencil && !visiblelighting) || visiblevolumes))
2824 qglDisable(GL_CULL_FACE);
2825 GL_DepthTest(visiblevolumes < 2);
2826 GL_Color(0.0, 0.0125, 0.1, 1);
2830 R_Shadow_Stage_ShadowVolumes();
2833 ent = r_refdef.worldentity;
2834 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2836 memset(&m, 0, sizeof(m));
2837 R_Mesh_Matrix(&ent->matrix);
2838 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2840 m.pointer_vertex = mesh->vertex3f;
2842 GL_LockArrays(0, mesh->numverts);
2843 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2845 // increment stencil if backface is behind depthbuffer
2846 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2847 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2848 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2849 c_rtcached_shadowmeshes++;
2850 c_rtcached_shadowtris += mesh->numtriangles;
2851 // decrement stencil if frontface is behind depthbuffer
2852 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2853 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2855 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2856 c_rtcached_shadowmeshes++;
2857 c_rtcached_shadowtris += mesh->numtriangles;
2858 GL_LockArrays(0, 0);
2861 else if (numsurfaces)
2863 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2864 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2866 if (r_drawentities.integer)
2868 for (i = 0;i < r_refdef.numentities;i++)
2870 ent = r_refdef.entities[i];
2872 if (r_shadow_cull.integer)
2874 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2876 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingLeafPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2879 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2881 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2882 // light emitting entities should not cast their own shadow
2883 if (VectorLength2(relativelightorigin) < 0.1)
2885 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2886 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2887 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2888 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2889 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2890 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2891 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2896 if (visiblelighting || !visiblevolumes)
2898 if (visiblelighting)
2900 qglEnable(GL_CULL_FACE);
2901 GL_DepthTest(visiblelighting < 2);
2902 GL_Color(0.1, 0.0125, 0, 1);
2905 R_Shadow_Stage_Light(usestencil);
2907 ent = r_refdef.worldentity;
2908 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2910 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2911 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2912 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2913 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2914 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2915 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2916 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2917 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2918 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2920 R_Mesh_Matrix(&ent->matrix);
2921 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2922 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, NULL, NULL, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, visiblelighting);
2925 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist, visiblelighting);
2927 if (r_drawentities.integer)
2929 for (i = 0;i < r_refdef.numentities;i++)
2931 ent = r_refdef.entities[i];
2932 // can't draw transparent entity lighting here because
2933 // transparent meshes are deferred for later
2934 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
2936 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2937 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2938 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2939 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2940 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2941 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2942 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2943 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2944 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, ent->model->nummodelsurfaces, ent->model->surfacelist, visiblelighting);
2951 void R_ShadowVolumeLighting(int visiblelighting, int visiblevolumes)
2957 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2958 R_Shadow_EditLights_Reload_f();
2960 if (visiblelighting || visiblevolumes)
2962 memset(&m, 0, sizeof(m));
2965 GL_BlendFunc(GL_ONE, GL_ONE);
2966 GL_DepthMask(false);
2967 qglCullFace(GL_FRONT); // this culls back
2970 R_Shadow_Stage_Begin();
2971 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2972 if (r_shadow_debuglight.integer >= 0)
2974 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2975 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2976 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
2979 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2980 if (light->flags & flag)
2981 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
2983 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2984 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
2986 if (visiblelighting || visiblevolumes)
2988 qglEnable(GL_CULL_FACE);
2989 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2992 R_Shadow_Stage_End();
2995 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2996 typedef struct suffixinfo_s
2999 qboolean flipx, flipy, flipdiagonal;
3002 static suffixinfo_t suffix[3][6] =
3005 {"px", false, false, false},
3006 {"nx", false, false, false},
3007 {"py", false, false, false},
3008 {"ny", false, false, false},
3009 {"pz", false, false, false},
3010 {"nz", false, false, false}
3013 {"posx", false, false, false},
3014 {"negx", false, false, false},
3015 {"posy", false, false, false},
3016 {"negy", false, false, false},
3017 {"posz", false, false, false},
3018 {"negz", false, false, false}
3021 {"rt", true, false, true},
3022 {"lf", false, true, true},
3023 {"ft", true, true, false},
3024 {"bk", false, false, false},
3025 {"up", true, false, true},
3026 {"dn", true, false, true}
3030 static int componentorder[4] = {0, 1, 2, 3};
3032 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3034 int i, j, cubemapsize;
3035 qbyte *cubemappixels, *image_rgba;
3036 rtexture_t *cubemaptexture;
3038 // must start 0 so the first loadimagepixels has no requested width/height
3040 cubemappixels = NULL;
3041 cubemaptexture = NULL;
3042 // keep trying different suffix groups (posx, px, rt) until one loads
3043 for (j = 0;j < 3 && !cubemappixels;j++)
3045 // load the 6 images in the suffix group
3046 for (i = 0;i < 6;i++)
3048 // generate an image name based on the base and and suffix
3049 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3051 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3053 // an image loaded, make sure width and height are equal
3054 if (image_width == image_height)
3056 // if this is the first image to load successfully, allocate the cubemap memory
3057 if (!cubemappixels && image_width >= 1)
3059 cubemapsize = image_width;
3060 // note this clears to black, so unavailable sides are black
3061 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3063 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3065 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);
3068 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3070 Mem_Free(image_rgba);
3074 // if a cubemap loaded, upload it
3077 if (!r_shadow_filters_texturepool)
3078 r_shadow_filters_texturepool = R_AllocTexturePool();
3079 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3080 Mem_Free(cubemappixels);
3084 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3085 for (j = 0;j < 3;j++)
3086 for (i = 0;i < 6;i++)
3087 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3088 Con_Print(" and was unable to find any of them.\n");
3090 return cubemaptexture;
3093 rtexture_t *R_Shadow_Cubemap(const char *basename)
3096 for (i = 0;i < numcubemaps;i++)
3097 if (!strcasecmp(cubemaps[i].basename, basename))
3098 return cubemaps[i].texture;
3099 if (i >= MAX_CUBEMAPS)
3102 strcpy(cubemaps[i].basename, basename);
3103 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3104 return cubemaps[i].texture;
3107 void R_Shadow_FreeCubemaps(void)
3110 R_FreeTexturePool(&r_shadow_filters_texturepool);
3113 dlight_t *R_Shadow_NewWorldLight(void)
3116 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3117 light->next = r_shadow_worldlightchain;
3118 r_shadow_worldlightchain = light;
3122 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)
3124 VectorCopy(origin, light->origin);
3125 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3126 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3127 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3128 light->color[0] = max(color[0], 0);
3129 light->color[1] = max(color[1], 0);
3130 light->color[2] = max(color[2], 0);
3131 light->radius = max(radius, 0);
3132 light->style = style;
3133 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3135 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3138 light->shadow = shadowenable;
3139 light->corona = corona;
3142 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3143 light->coronasizescale = coronasizescale;
3144 light->ambientscale = ambientscale;
3145 light->diffusescale = diffusescale;
3146 light->specularscale = specularscale;
3147 light->flags = flags;
3148 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3150 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3153 void R_Shadow_FreeWorldLight(dlight_t *light)
3155 dlight_t **lightpointer;
3156 R_RTLight_Uncompile(&light->rtlight);
3157 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3158 if (*lightpointer != light)
3159 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3160 *lightpointer = light->next;
3164 void R_Shadow_ClearWorldLights(void)
3166 while (r_shadow_worldlightchain)
3167 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3168 r_shadow_selectedlight = NULL;
3169 R_Shadow_FreeCubemaps();
3172 void R_Shadow_SelectLight(dlight_t *light)
3174 if (r_shadow_selectedlight)
3175 r_shadow_selectedlight->selected = false;
3176 r_shadow_selectedlight = light;
3177 if (r_shadow_selectedlight)
3178 r_shadow_selectedlight->selected = true;
3181 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3183 float scale = r_editlights_cursorgrid.value * 0.5f;
3184 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);
3187 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3190 const dlight_t *light;
3193 if (light->selected)
3194 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3197 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);
3200 void R_Shadow_DrawLightSprites(void)
3206 for (i = 0;i < 5;i++)
3208 lighttextures[i] = NULL;
3209 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3210 lighttextures[i] = pic->tex;
3213 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3214 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3215 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3218 void R_Shadow_SelectLightInView(void)
3220 float bestrating, rating, temp[3];
3221 dlight_t *best, *light;
3224 for (light = r_shadow_worldlightchain;light;light = light->next)
3226 VectorSubtract(light->origin, r_vieworigin, temp);
3227 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3230 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3231 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3233 bestrating = rating;
3238 R_Shadow_SelectLight(best);
3241 void R_Shadow_LoadWorldLights(void)
3243 int n, a, style, shadow, flags;
3244 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3245 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3246 if (r_refdef.worldmodel == NULL)
3248 Con_Print("No map loaded.\n");
3251 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3252 strlcat (name, ".rtlights", sizeof (name));
3253 lightsstring = FS_LoadFile(name, tempmempool, false);
3263 for (;COM_Parse(t, true) && strcmp(
3264 if (COM_Parse(t, true))
3266 if (com_token[0] == '!')
3269 origin[0] = atof(com_token+1);
3272 origin[0] = atof(com_token);
3277 while (*s && *s != '\n' && *s != '\r')
3283 // check for modifier flags
3290 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);
3293 flags = LIGHTFLAG_REALTIMEMODE;
3301 coronasizescale = 0.25f;
3303 VectorClear(angles);
3306 if (a < 9 || !strcmp(cubemapname, "\"\""))
3308 // remove quotes on cubemapname
3309 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3311 cubemapname[strlen(cubemapname)-1] = 0;
3312 strcpy(cubemapname, cubemapname + 1);
3316 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);
3319 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3320 radius *= r_editlights_rtlightssizescale.value;
3321 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3329 Con_Printf("invalid rtlights file \"%s\"\n", name);
3330 Mem_Free(lightsstring);
3334 void R_Shadow_SaveWorldLights(void)
3337 int bufchars, bufmaxchars;
3339 char name[MAX_QPATH];
3341 if (!r_shadow_worldlightchain)
3343 if (r_refdef.worldmodel == NULL)
3345 Con_Print("No map loaded.\n");
3348 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3349 strlcat (name, ".rtlights", sizeof (name));
3350 bufchars = bufmaxchars = 0;
3352 for (light = r_shadow_worldlightchain;light;light = light->next)
3354 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3355 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);
3356 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3357 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]);
3359 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);
3360 if (bufchars + (int) strlen(line) > bufmaxchars)
3362 bufmaxchars = bufchars + strlen(line) + 2048;
3364 buf = Mem_Alloc(tempmempool, bufmaxchars);
3368 memcpy(buf, oldbuf, bufchars);
3374 memcpy(buf + bufchars, line, strlen(line));
3375 bufchars += strlen(line);
3379 FS_WriteFile(name, buf, bufchars);
3384 void R_Shadow_LoadLightsFile(void)
3387 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3388 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3389 if (r_refdef.worldmodel == NULL)
3391 Con_Print("No map loaded.\n");
3394 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3395 strlcat (name, ".lights", sizeof (name));
3396 lightsstring = FS_LoadFile(name, tempmempool, false);
3404 while (*s && *s != '\n' && *s != '\r')
3410 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);
3414 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);
3417 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3418 radius = bound(15, radius, 4096);
3419 VectorScale(color, (2.0f / (8388608.0f)), color);
3420 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3428 Con_Printf("invalid lights file \"%s\"\n", name);
3429 Mem_Free(lightsstring);
3433 // tyrlite/hmap2 light types in the delay field
3434 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3436 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3438 int entnum, style, islight, skin, pflags, effects, type, n;
3441 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3442 char key[256], value[1024];
3444 if (r_refdef.worldmodel == NULL)
3446 Con_Print("No map loaded.\n");
3449 // try to load a .ent file first
3450 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3451 strlcat (key, ".ent", sizeof (key));
3452 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3453 // and if that is not found, fall back to the bsp file entity string
3455 data = r_refdef.worldmodel->brush.entities;
3458 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3460 type = LIGHTTYPE_MINUSX;
3461 origin[0] = origin[1] = origin[2] = 0;
3462 originhack[0] = originhack[1] = originhack[2] = 0;
3463 angles[0] = angles[1] = angles[2] = 0;
3464 color[0] = color[1] = color[2] = 1;
3465 light[0] = light[1] = light[2] = 1;light[3] = 300;
3466 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3476 if (!COM_ParseToken(&data, false))
3478 if (com_token[0] == '}')
3479 break; // end of entity
3480 if (com_token[0] == '_')
3481 strcpy(key, com_token + 1);
3483 strcpy(key, com_token);
3484 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3485 key[strlen(key)-1] = 0;
3486 if (!COM_ParseToken(&data, false))
3488 strcpy(value, com_token);
3490 // now that we have the key pair worked out...
3491 if (!strcmp("light", key))
3493 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3497 light[0] = vec[0] * (1.0f / 256.0f);
3498 light[1] = vec[0] * (1.0f / 256.0f);
3499 light[2] = vec[0] * (1.0f / 256.0f);
3505 light[0] = vec[0] * (1.0f / 255.0f);
3506 light[1] = vec[1] * (1.0f / 255.0f);
3507 light[2] = vec[2] * (1.0f / 255.0f);
3511 else if (!strcmp("delay", key))
3513 else if (!strcmp("origin", key))
3514 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3515 else if (!strcmp("angle", key))
3516 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3517 else if (!strcmp("angles", key))
3518 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3519 else if (!strcmp("color", key))
3520 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3521 else if (!strcmp("wait", key))
3522 fadescale = atof(value);
3523 else if (!strcmp("classname", key))
3525 if (!strncmp(value, "light", 5))
3528 if (!strcmp(value, "light_fluoro"))
3533 overridecolor[0] = 1;
3534 overridecolor[1] = 1;
3535 overridecolor[2] = 1;
3537 if (!strcmp(value, "light_fluorospark"))
3542 overridecolor[0] = 1;
3543 overridecolor[1] = 1;
3544 overridecolor[2] = 1;
3546 if (!strcmp(value, "light_globe"))
3551 overridecolor[0] = 1;
3552 overridecolor[1] = 0.8;
3553 overridecolor[2] = 0.4;
3555 if (!strcmp(value, "light_flame_large_yellow"))
3560 overridecolor[0] = 1;
3561 overridecolor[1] = 0.5;
3562 overridecolor[2] = 0.1;
3564 if (!strcmp(value, "light_flame_small_yellow"))
3569 overridecolor[0] = 1;
3570 overridecolor[1] = 0.5;
3571 overridecolor[2] = 0.1;
3573 if (!strcmp(value, "light_torch_small_white"))
3578 overridecolor[0] = 1;
3579 overridecolor[1] = 0.5;
3580 overridecolor[2] = 0.1;
3582 if (!strcmp(value, "light_torch_small_walltorch"))
3587 overridecolor[0] = 1;
3588 overridecolor[1] = 0.5;
3589 overridecolor[2] = 0.1;
3593 else if (!strcmp("style", key))
3594 style = atoi(value);
3595 else if (r_refdef.worldmodel->type == mod_brushq3)
3597 if (!strcmp("scale", key))
3598 lightscale = atof(value);
3599 if (!strcmp("fade", key))
3600 fadescale = atof(value);
3602 else if (!strcmp("skin", key))
3603 skin = (int)atof(value);
3604 else if (!strcmp("pflags", key))
3605 pflags = (int)atof(value);
3606 else if (!strcmp("effects", key))
3607 effects = (int)atof(value);
3611 if (lightscale <= 0)
3615 if (color[0] == color[1] && color[0] == color[2])
3617 color[0] *= overridecolor[0];
3618 color[1] *= overridecolor[1];
3619 color[2] *= overridecolor[2];
3621 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3622 color[0] = color[0] * light[0];
3623 color[1] = color[1] * light[1];
3624 color[2] = color[2] * light[2];
3627 case LIGHTTYPE_MINUSX:
3629 case LIGHTTYPE_RECIPX:
3631 VectorScale(color, (1.0f / 16.0f), color);
3633 case LIGHTTYPE_RECIPXX:
3635 VectorScale(color, (1.0f / 16.0f), color);
3638 case LIGHTTYPE_NONE:
3642 case LIGHTTYPE_MINUSXX:
3645 VectorAdd(origin, originhack, origin);
3647 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);
3650 Mem_Free(entfiledata);
3654 void R_Shadow_SetCursorLocationForView(void)
3657 vec3_t dest, endpos;
3659 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3660 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3661 if (trace.fraction < 1)
3663 dist = trace.fraction * r_editlights_cursordistance.value;
3664 push = r_editlights_cursorpushback.value;
3668 VectorMA(trace.endpos, push, r_viewforward, endpos);
3669 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3671 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3672 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3673 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3676 void R_Shadow_UpdateWorldLightSelection(void)
3678 if (r_editlights.integer)
3680 R_Shadow_SetCursorLocationForView();
3681 R_Shadow_SelectLightInView();
3682 R_Shadow_DrawLightSprites();
3685 R_Shadow_SelectLight(NULL);
3688 void R_Shadow_EditLights_Clear_f(void)
3690 R_Shadow_ClearWorldLights();
3693 void R_Shadow_EditLights_Reload_f(void)
3695 if (!r_refdef.worldmodel)
3697 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3698 R_Shadow_ClearWorldLights();
3699 R_Shadow_LoadWorldLights();
3700 if (r_shadow_worldlightchain == NULL)
3702 R_Shadow_LoadLightsFile();
3703 if (r_shadow_worldlightchain == NULL)
3704 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3708 void R_Shadow_EditLights_Save_f(void)
3710 if (!r_refdef.worldmodel)
3712 R_Shadow_SaveWorldLights();
3715 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3717 R_Shadow_ClearWorldLights();
3718 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3721 void R_Shadow_EditLights_ImportLightsFile_f(void)
3723 R_Shadow_ClearWorldLights();
3724 R_Shadow_LoadLightsFile();
3727 void R_Shadow_EditLights_Spawn_f(void)
3730 if (!r_editlights.integer)
3732 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3735 if (Cmd_Argc() != 1)
3737 Con_Print("r_editlights_spawn does not take parameters\n");
3740 color[0] = color[1] = color[2] = 1;
3741 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3744 void R_Shadow_EditLights_Edit_f(void)
3746 vec3_t origin, angles, color;
3747 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3748 int style, shadows, flags, normalmode, realtimemode;
3749 char cubemapname[1024];
3750 if (!r_editlights.integer)
3752 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3755 if (!r_shadow_selectedlight)
3757 Con_Print("No selected light.\n");
3760 VectorCopy(r_shadow_selectedlight->origin, origin);
3761 VectorCopy(r_shadow_selectedlight->angles, angles);
3762 VectorCopy(r_shadow_selectedlight->color, color);
3763 radius = r_shadow_selectedlight->radius;
3764 style = r_shadow_selectedlight->style;
3765 if (r_shadow_selectedlight->cubemapname)
3766 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3769 shadows = r_shadow_selectedlight->shadow;
3770 corona = r_shadow_selectedlight->corona;
3771 coronasizescale = r_shadow_selectedlight->coronasizescale;
3772 ambientscale = r_shadow_selectedlight->ambientscale;
3773 diffusescale = r_shadow_selectedlight->diffusescale;
3774 specularscale = r_shadow_selectedlight->specularscale;
3775 flags = r_shadow_selectedlight->flags;
3776 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3777 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3778 if (!strcmp(Cmd_Argv(1), "origin"))
3780 if (Cmd_Argc() != 5)
3782 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3785 origin[0] = atof(Cmd_Argv(2));
3786 origin[1] = atof(Cmd_Argv(3));
3787 origin[2] = atof(Cmd_Argv(4));
3789 else if (!strcmp(Cmd_Argv(1), "originx"))
3791 if (Cmd_Argc() != 3)
3793 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3796 origin[0] = atof(Cmd_Argv(2));
3798 else if (!strcmp(Cmd_Argv(1), "originy"))
3800 if (Cmd_Argc() != 3)
3802 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3805 origin[1] = atof(Cmd_Argv(2));
3807 else if (!strcmp(Cmd_Argv(1), "originz"))
3809 if (Cmd_Argc() != 3)
3811 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3814 origin[2] = atof(Cmd_Argv(2));
3816 else if (!strcmp(Cmd_Argv(1), "move"))
3818 if (Cmd_Argc() != 5)
3820 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3823 origin[0] += atof(Cmd_Argv(2));
3824 origin[1] += atof(Cmd_Argv(3));
3825 origin[2] += atof(Cmd_Argv(4));
3827 else if (!strcmp(Cmd_Argv(1), "movex"))
3829 if (Cmd_Argc() != 3)
3831 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3834 origin[0] += atof(Cmd_Argv(2));
3836 else if (!strcmp(Cmd_Argv(1), "movey"))
3838 if (Cmd_Argc() != 3)
3840 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3843 origin[1] += atof(Cmd_Argv(2));
3845 else if (!strcmp(Cmd_Argv(1), "movez"))
3847 if (Cmd_Argc() != 3)
3849 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3852 origin[2] += atof(Cmd_Argv(2));
3854 else if (!strcmp(Cmd_Argv(1), "angles"))
3856 if (Cmd_Argc() != 5)
3858 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3861 angles[0] = atof(Cmd_Argv(2));
3862 angles[1] = atof(Cmd_Argv(3));
3863 angles[2] = atof(Cmd_Argv(4));
3865 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3867 if (Cmd_Argc() != 3)
3869 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3872 angles[0] = atof(Cmd_Argv(2));
3874 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3876 if (Cmd_Argc() != 3)
3878 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3881 angles[1] = atof(Cmd_Argv(2));
3883 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3885 if (Cmd_Argc() != 3)
3887 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3890 angles[2] = atof(Cmd_Argv(2));
3892 else if (!strcmp(Cmd_Argv(1), "color"))
3894 if (Cmd_Argc() != 5)
3896 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3899 color[0] = atof(Cmd_Argv(2));
3900 color[1] = atof(Cmd_Argv(3));
3901 color[2] = atof(Cmd_Argv(4));
3903 else if (!strcmp(Cmd_Argv(1), "radius"))
3905 if (Cmd_Argc() != 3)
3907 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3910 radius = atof(Cmd_Argv(2));
3912 else if (!strcmp(Cmd_Argv(1), "style"))
3914 if (Cmd_Argc() != 3)
3916 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3919 style = atoi(Cmd_Argv(2));
3921 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3925 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3928 if (Cmd_Argc() == 3)
3929 strcpy(cubemapname, Cmd_Argv(2));
3933 else if (!strcmp(Cmd_Argv(1), "shadows"))
3935 if (Cmd_Argc() != 3)
3937 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3940 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3942 else if (!strcmp(Cmd_Argv(1), "corona"))
3944 if (Cmd_Argc() != 3)
3946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3949 corona = atof(Cmd_Argv(2));
3951 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3953 if (Cmd_Argc() != 3)
3955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3958 coronasizescale = atof(Cmd_Argv(2));
3960 else if (!strcmp(Cmd_Argv(1), "ambient"))
3962 if (Cmd_Argc() != 3)
3964 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3967 ambientscale = atof(Cmd_Argv(2));
3969 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3971 if (Cmd_Argc() != 3)
3973 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3976 diffusescale = atof(Cmd_Argv(2));
3978 else if (!strcmp(Cmd_Argv(1), "specular"))
3980 if (Cmd_Argc() != 3)
3982 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3985 specularscale = atof(Cmd_Argv(2));
3987 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3989 if (Cmd_Argc() != 3)
3991 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3994 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3996 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3998 if (Cmd_Argc() != 3)
4000 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4003 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4007 Con_Print("usage: r_editlights_edit [property] [value]\n");
4008 Con_Print("Selected light's properties:\n");
4009 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4010 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4011 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4012 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4013 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4014 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4015 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4016 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4017 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4018 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4019 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4020 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4021 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4022 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4025 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4026 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4029 void R_Shadow_EditLights_EditAll_f(void)
4033 if (!r_editlights.integer)
4035 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4039 for (light = r_shadow_worldlightchain;light;light = light->next)
4041 R_Shadow_SelectLight(light);
4042 R_Shadow_EditLights_Edit_f();
4046 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4048 int lightnumber, lightcount;
4052 if (!r_editlights.integer)
4058 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4059 if (light == r_shadow_selectedlight)
4060 lightnumber = lightcount;
4061 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;
4062 if (r_shadow_selectedlight == NULL)
4064 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4065 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;
4066 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;
4067 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;
4068 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4069 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4070 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4071 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;
4072 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4073 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4074 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4075 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4076 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4077 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;
4078 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;
4081 void R_Shadow_EditLights_ToggleShadow_f(void)
4083 if (!r_editlights.integer)
4085 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4088 if (!r_shadow_selectedlight)
4090 Con_Print("No selected light.\n");
4093 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);
4096 void R_Shadow_EditLights_ToggleCorona_f(void)
4098 if (!r_editlights.integer)
4100 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4103 if (!r_shadow_selectedlight)
4105 Con_Print("No selected light.\n");
4108 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);
4111 void R_Shadow_EditLights_Remove_f(void)
4113 if (!r_editlights.integer)
4115 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4118 if (!r_shadow_selectedlight)
4120 Con_Print("No selected light.\n");
4123 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4124 r_shadow_selectedlight = NULL;
4127 void R_Shadow_EditLights_Help_f(void)
4130 "Documentation on r_editlights system:\n"
4132 "r_editlights : enable/disable editing mode\n"
4133 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4134 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4135 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4136 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4137 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4138 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4139 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4141 "r_editlights_help : this help\n"
4142 "r_editlights_clear : remove all lights\n"
4143 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4144 "r_editlights_save : save to .rtlights file\n"
4145 "r_editlights_spawn : create a light with default settings\n"
4146 "r_editlights_edit command : edit selected light - more documentation below\n"
4147 "r_editlights_remove : remove selected light\n"
4148 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4149 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4150 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4152 "origin x y z : set light location\n"
4153 "originx x: set x component of light location\n"
4154 "originy y: set y component of light location\n"
4155 "originz z: set z component of light location\n"
4156 "move x y z : adjust light location\n"
4157 "movex x: adjust x component of light location\n"
4158 "movey y: adjust y component of light location\n"
4159 "movez z: adjust z component of light location\n"
4160 "angles x y z : set light angles\n"
4161 "anglesx x: set x component of light angles\n"
4162 "anglesy y: set y component of light angles\n"
4163 "anglesz z: set z component of light angles\n"
4164 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4165 "radius radius : set radius (size) of light\n"
4166 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4167 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4168 "shadows 1/0 : turn on/off shadows\n"
4169 "corona n : set corona intensity\n"
4170 "coronasize n : set corona size (0-1)\n"
4171 "ambient n : set ambient intensity (0-1)\n"
4172 "diffuse n : set diffuse intensity (0-1)\n"
4173 "specular n : set specular intensity (0-1)\n"
4174 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4175 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4176 "<nothing> : print light properties to console\n"
4180 void R_Shadow_EditLights_CopyInfo_f(void)
4182 if (!r_editlights.integer)
4184 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4187 if (!r_shadow_selectedlight)
4189 Con_Print("No selected light.\n");
4192 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4193 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4194 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4195 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4196 if (r_shadow_selectedlight->cubemapname)
4197 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4199 r_shadow_bufferlight.cubemapname[0] = 0;
4200 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4201 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4202 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4203 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4204 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4205 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4206 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4209 void R_Shadow_EditLights_PasteInfo_f(void)
4211 if (!r_editlights.integer)
4213 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4216 if (!r_shadow_selectedlight)
4218 Con_Print("No selected light.\n");
4221 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);
4224 void R_Shadow_EditLights_Init(void)
4226 Cvar_RegisterVariable(&r_editlights);
4227 Cvar_RegisterVariable(&r_editlights_cursordistance);
4228 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4229 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4230 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4231 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4232 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4233 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4234 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4235 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4236 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4237 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4238 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4239 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4240 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4241 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4242 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4243 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4244 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4245 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4246 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4247 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);