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);
1069 void R_Shadow_Stage_Light(int shadowtest)
1072 memset(&m, 0, sizeof(m));
1074 GL_BlendFunc(GL_ONE, GL_ONE);
1075 GL_DepthMask(false);
1077 qglPolygonOffset(0, 0);
1078 //qglDisable(GL_POLYGON_OFFSET_FILL);
1079 GL_Color(1, 1, 1, 1);
1080 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1081 qglDepthFunc(GL_EQUAL);
1082 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1083 qglEnable(GL_CULL_FACE);
1085 qglEnable(GL_STENCIL_TEST);
1087 qglDisable(GL_STENCIL_TEST);
1088 if (gl_support_stenciltwoside)
1089 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1091 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1092 // only draw light where this geometry was already rendered AND the
1093 // stencil is 128 (values other than this mean shadow)
1094 qglStencilFunc(GL_EQUAL, 128, ~0);
1095 r_shadowstage = SHADOWSTAGE_LIGHT;
1098 void R_Shadow_Stage_End(void)
1101 memset(&m, 0, sizeof(m));
1103 GL_BlendFunc(GL_ONE, GL_ZERO);
1106 qglPolygonOffset(0, 0);
1107 //qglDisable(GL_POLYGON_OFFSET_FILL);
1108 GL_Color(1, 1, 1, 1);
1109 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1110 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1111 qglDepthFunc(GL_LEQUAL);
1112 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1113 qglDisable(GL_STENCIL_TEST);
1114 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1115 if (gl_support_stenciltwoside)
1116 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1118 qglStencilFunc(GL_ALWAYS, 128, ~0);
1119 r_shadowstage = SHADOWSTAGE_NONE;
1122 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1124 int i, ix1, iy1, ix2, iy2;
1125 float x1, y1, x2, y2, x, y, f;
1126 vec3_t smins, smaxs;
1128 if (!r_shadow_scissor.integer)
1130 // if view is inside the box, just say yes it's visible
1131 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1133 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1136 for (i = 0;i < 3;i++)
1138 if (r_viewforward[i] >= 0)
1149 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1150 if (DotProduct(r_viewforward, v2) <= f)
1152 // entirely behind nearclip plane
1155 if (DotProduct(r_viewforward, v) >= f)
1157 // entirely infront of nearclip plane
1158 x1 = y1 = x2 = y2 = 0;
1159 for (i = 0;i < 8;i++)
1161 v[0] = (i & 1) ? mins[0] : maxs[0];
1162 v[1] = (i & 2) ? mins[1] : maxs[1];
1163 v[2] = (i & 4) ? mins[2] : maxs[2];
1165 GL_TransformToScreen(v, v2);
1166 //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]);
1185 // clipped by nearclip plane
1186 // this is nasty and crude...
1187 // create viewspace bbox
1188 for (i = 0;i < 8;i++)
1190 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1191 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1192 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1193 v2[0] = -DotProduct(v, r_viewleft);
1194 v2[1] = DotProduct(v, r_viewup);
1195 v2[2] = DotProduct(v, r_viewforward);
1198 if (smins[0] > v2[0]) smins[0] = v2[0];
1199 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1200 if (smins[1] > v2[1]) smins[1] = v2[1];
1201 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1202 if (smins[2] > v2[2]) smins[2] = v2[2];
1203 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1207 smins[0] = smaxs[0] = v2[0];
1208 smins[1] = smaxs[1] = v2[1];
1209 smins[2] = smaxs[2] = v2[2];
1212 // now we have a bbox in viewspace
1213 // clip it to the view plane
1216 // return true if that culled the box
1217 if (smins[2] >= smaxs[2])
1219 // ok some of it is infront of the view, transform each corner back to
1220 // worldspace and then to screenspace and make screen rect
1221 // initialize these variables just to avoid compiler warnings
1222 x1 = y1 = x2 = y2 = 0;
1223 for (i = 0;i < 8;i++)
1225 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1226 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1227 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1228 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1229 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1230 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1232 GL_TransformToScreen(v, v2);
1233 //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]);
1250 // this code doesn't handle boxes with any points behind view properly
1251 x1 = 1000;x2 = -1000;
1252 y1 = 1000;y2 = -1000;
1253 for (i = 0;i < 8;i++)
1255 v[0] = (i & 1) ? mins[0] : maxs[0];
1256 v[1] = (i & 2) ? mins[1] : maxs[1];
1257 v[2] = (i & 4) ? mins[2] : maxs[2];
1259 GL_TransformToScreen(v, v2);
1260 //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]);
1278 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1279 if (ix1 < r_view_x) ix1 = r_view_x;
1280 if (iy1 < r_view_y) iy1 = r_view_y;
1281 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1282 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1283 if (ix2 <= ix1 || iy2 <= iy1)
1285 // set up the scissor rectangle
1286 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1287 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1288 //qglEnable(GL_SCISSOR_TEST);
1293 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1295 float *color4f = varray_color4f;
1296 float dist, dot, intensity, v[3], n[3];
1297 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1299 Matrix4x4_Transform(m, vertex3f, v);
1300 if ((dist = DotProduct(v, v)) < 1)
1302 Matrix4x4_Transform3x3(m, normal3f, n);
1303 if ((dot = DotProduct(n, v)) > 0)
1306 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1307 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1308 VectorScale(lightcolor, intensity, color4f);
1313 VectorClear(color4f);
1319 VectorClear(color4f);
1325 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1327 float *color4f = varray_color4f;
1328 float dist, dot, intensity, v[3], n[3];
1329 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1331 Matrix4x4_Transform(m, vertex3f, v);
1332 if ((dist = fabs(v[2])) < 1)
1334 Matrix4x4_Transform3x3(m, normal3f, n);
1335 if ((dot = DotProduct(n, v)) > 0)
1337 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1338 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1339 VectorScale(lightcolor, intensity, color4f);
1344 VectorClear(color4f);
1350 VectorClear(color4f);
1356 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1358 float *color4f = varray_color4f;
1359 float dot, intensity, v[3], n[3];
1360 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1362 Matrix4x4_Transform(m, vertex3f, v);
1363 Matrix4x4_Transform3x3(m, normal3f, n);
1364 if ((dot = DotProduct(n, v)) > 0)
1366 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1367 VectorScale(lightcolor, intensity, color4f);
1372 VectorClear(color4f);
1378 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1380 float *color4f = varray_color4f;
1381 float dist, intensity, v[3];
1382 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1384 Matrix4x4_Transform(m, vertex3f, v);
1385 if ((dist = DotProduct(v, v)) < 1)
1388 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1389 VectorScale(lightcolor, intensity, color4f);
1394 VectorClear(color4f);
1400 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1402 float *color4f = varray_color4f;
1403 float dist, intensity, v[3];
1404 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1406 Matrix4x4_Transform(m, vertex3f, v);
1407 if ((dist = fabs(v[2])) < 1)
1409 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1410 VectorScale(lightcolor, intensity, color4f);
1415 VectorClear(color4f);
1421 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1422 #define USETEXMATRIX
1424 #ifndef USETEXMATRIX
1425 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1426 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1427 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1431 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1432 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1433 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1440 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1444 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1445 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1453 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)
1457 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1459 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1460 // the cubemap normalizes this for us
1461 out3f[0] = DotProduct(svector3f, lightdir);
1462 out3f[1] = DotProduct(tvector3f, lightdir);
1463 out3f[2] = DotProduct(normal3f, lightdir);
1467 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)
1470 float lightdir[3], eyedir[3], halfdir[3];
1471 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1473 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1474 VectorNormalizeFast(lightdir);
1475 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1476 VectorNormalizeFast(eyedir);
1477 VectorAdd(lightdir, eyedir, halfdir);
1478 // the cubemap normalizes this for us
1479 out3f[0] = DotProduct(svector3f, halfdir);
1480 out3f[1] = DotProduct(tvector3f, halfdir);
1481 out3f[2] = DotProduct(normal3f, halfdir);
1485 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)
1488 float color[3], color2[3], colorscale;
1490 if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && specularscale > 0)
1491 specularscale = specularscale * r_shadow_glossintensity.value;
1492 else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && specularscale > 0)
1494 glosstexture = r_texture_white;
1495 specularscale = specularscale * r_shadow_gloss2intensity.value;
1499 glosstexture = r_texture_black;
1502 if ((ambientscale + diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1505 basetexture = r_texture_white;
1507 bumptexture = r_texture_blanknormalmap;
1508 if (!lightcolorbase)
1509 lightcolorbase = vec3_origin;
1510 if (!lightcolorpants)
1511 lightcolorpants = vec3_origin;
1512 if (!lightcolorshirt)
1513 lightcolorshirt = vec3_origin;
1514 if (visiblelighting)
1517 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1518 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1519 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1521 // TODO: add direct pants/shirt rendering
1522 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1523 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);
1524 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1525 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);
1527 bumptexture = r_texture_blanknormalmap;
1529 glosstexture = r_texture_white;
1532 colorscale = ambientscale;
1533 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1536 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1539 else if (r_textureunits.integer >= 4 && lightcubemap)
1542 else if (r_textureunits.integer >= 3 && !lightcubemap)
1547 VectorScale(lightcolorbase, colorscale, color2);
1548 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1553 colorscale = diffusescale;
1554 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1556 // 3/2 3D combine path (Geforce3, Radeon 8500)
1559 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1561 // 1/2/2 3D combine path (original Radeon)
1564 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1566 // 2/2 3D combine path (original Radeon)
1569 else if (r_textureunits.integer >= 4)
1571 // 4/2 2D combine path (Geforce3, Radeon 8500)
1576 // 2/2/2 2D combine path (any dot3 card)
1579 VectorScale(lightcolorbase, colorscale, color2);
1580 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1583 if (specularscale && glosstexture != r_texture_black)
1585 //if (gl_support_blendsquare)
1587 colorscale = specularscale;
1588 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1590 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1594 VectorScale(lightcolorbase, colorscale, color2);
1595 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1602 // TODO: add direct pants/shirt rendering
1603 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1604 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);
1605 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1606 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);
1609 VectorScale(lightcolorbase, ambientscale, color2);
1610 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1615 VectorScale(lightcolorbase, diffusescale, color2);
1616 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1622 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1623 memset(&m, 0, sizeof(m));
1624 m.pointer_vertex = vertex3f;
1626 GL_LockArrays(firstvertex, numvertices);
1627 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1628 GL_LockArrays(0, 0);
1632 // FIXME: support EF_NODEPTHTEST
1633 GL_DepthMask(false);
1635 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1637 unsigned int perm, prog;
1638 // GLSL shader path (GFFX5200, Radeon 9500)
1639 memset(&m, 0, sizeof(m));
1640 m.pointer_vertex = vertex3f;
1641 m.pointer_texcoord[0] = texcoord2f;
1642 m.pointer_texcoord3f[1] = svector3f;
1643 m.pointer_texcoord3f[2] = tvector3f;
1644 m.pointer_texcoord3f[3] = normal3f;
1645 m.tex[0] = R_GetTexture(bumptexture);
1646 m.tex[1] = R_GetTexture(basetexture);
1647 m.tex[2] = R_GetTexture(glosstexture);
1648 m.texcubemap[3] = R_GetTexture(lightcubemap);
1649 // TODO: support fog (after renderer is converted to texture fog)
1650 m.tex[4] = R_GetTexture(r_texture_white);
1651 m.texmatrix[3] = *matrix_modeltolight;
1653 GL_BlendFunc(GL_ONE, GL_ONE);
1654 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1657 // only add a feature to the permutation if that permutation exists
1658 // (otherwise it might end up not using a shader at all, which looks
1659 // worse than using less features)
1660 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1661 perm |= SHADERPERMUTATION_SPECULAR;
1662 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1663 // perm |= SHADERPERMUTATION_FOG;
1664 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1665 perm |= SHADERPERMUTATION_CUBEFILTER;
1666 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1667 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1668 prog = r_shadow_program_light[perm];
1669 qglUseProgramObjectARB(prog);CHECKGLERROR
1670 // TODO: support fog (after renderer is converted to texture fog)
1671 if (perm & SHADERPERMUTATION_FOG)
1673 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1675 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1676 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1677 if (perm & SHADERPERMUTATION_SPECULAR)
1679 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1680 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1682 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1683 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1684 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1686 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1688 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1690 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1691 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1694 GL_LockArrays(firstvertex, numvertices);
1695 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1697 c_rt_lighttris += numtriangles;
1698 // TODO: add direct pants/shirt rendering
1699 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1701 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1702 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1703 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1705 c_rt_lighttris += numtriangles;
1707 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1709 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1710 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1711 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1713 c_rt_lighttris += numtriangles;
1715 GL_LockArrays(0, 0);
1716 qglUseProgramObjectARB(0);
1717 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1718 qglBegin(GL_TRIANGLES);
1722 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1724 // TODO: add direct pants/shirt rendering
1725 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1726 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);
1727 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1728 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);
1730 bumptexture = r_texture_blanknormalmap;
1732 glosstexture = r_texture_white;
1736 colorscale = ambientscale;
1737 // colorscale accounts for how much we multiply the brightness
1740 // mult is how many times the final pass of the lighting will be
1741 // performed to get more brightness than otherwise possible.
1743 // Limit mult to 64 for sanity sake.
1744 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1746 // 3 3D combine path (Geforce3, Radeon 8500)
1747 memset(&m, 0, sizeof(m));
1748 m.pointer_vertex = vertex3f;
1749 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1751 m.pointer_texcoord3f[0] = vertex3f;
1752 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1754 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1755 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1757 m.tex[1] = R_GetTexture(basetexture);
1758 m.pointer_texcoord[1] = texcoord2f;
1759 m.texcubemap[2] = R_GetTexture(lightcubemap);
1761 m.pointer_texcoord3f[2] = vertex3f;
1762 m.texmatrix[2] = *matrix_modeltolight;
1764 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1765 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1767 GL_BlendFunc(GL_ONE, GL_ONE);
1769 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1771 // 2 3D combine path (Geforce3, original Radeon)
1772 memset(&m, 0, sizeof(m));
1773 m.pointer_vertex = vertex3f;
1774 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1776 m.pointer_texcoord3f[0] = vertex3f;
1777 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1779 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1780 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1782 m.tex[1] = R_GetTexture(basetexture);
1783 m.pointer_texcoord[1] = texcoord2f;
1784 GL_BlendFunc(GL_ONE, GL_ONE);
1786 else if (r_textureunits.integer >= 4 && lightcubemap)
1788 // 4 2D combine path (Geforce3, Radeon 8500)
1789 memset(&m, 0, sizeof(m));
1790 m.pointer_vertex = vertex3f;
1791 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1793 m.pointer_texcoord3f[0] = vertex3f;
1794 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1796 m.pointer_texcoord[0] = varray_texcoord2f[0];
1797 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1799 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1801 m.pointer_texcoord3f[1] = vertex3f;
1802 m.texmatrix[1] = *matrix_modeltoattenuationz;
1804 m.pointer_texcoord[1] = varray_texcoord2f[1];
1805 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1807 m.tex[2] = R_GetTexture(basetexture);
1808 m.pointer_texcoord[2] = texcoord2f;
1811 m.texcubemap[3] = R_GetTexture(lightcubemap);
1813 m.pointer_texcoord3f[3] = vertex3f;
1814 m.texmatrix[3] = *matrix_modeltolight;
1816 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1817 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1820 GL_BlendFunc(GL_ONE, GL_ONE);
1822 else if (r_textureunits.integer >= 3 && !lightcubemap)
1824 // 3 2D combine path (Geforce3, original Radeon)
1825 memset(&m, 0, sizeof(m));
1826 m.pointer_vertex = vertex3f;
1827 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1829 m.pointer_texcoord3f[0] = vertex3f;
1830 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1832 m.pointer_texcoord[0] = varray_texcoord2f[0];
1833 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1835 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1837 m.pointer_texcoord3f[1] = vertex3f;
1838 m.texmatrix[1] = *matrix_modeltoattenuationz;
1840 m.pointer_texcoord[1] = varray_texcoord2f[1];
1841 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1843 m.tex[2] = R_GetTexture(basetexture);
1844 m.pointer_texcoord[2] = texcoord2f;
1845 GL_BlendFunc(GL_ONE, GL_ONE);
1849 // 2/2/2 2D combine path (any dot3 card)
1850 memset(&m, 0, sizeof(m));
1851 m.pointer_vertex = vertex3f;
1852 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1854 m.pointer_texcoord3f[0] = vertex3f;
1855 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1857 m.pointer_texcoord[0] = varray_texcoord2f[0];
1858 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1860 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1862 m.pointer_texcoord3f[1] = vertex3f;
1863 m.texmatrix[1] = *matrix_modeltoattenuationz;
1865 m.pointer_texcoord[1] = varray_texcoord2f[1];
1866 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1869 GL_ColorMask(0,0,0,1);
1870 GL_BlendFunc(GL_ONE, GL_ZERO);
1871 GL_LockArrays(firstvertex, numvertices);
1872 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1873 GL_LockArrays(0, 0);
1875 c_rt_lighttris += numtriangles;
1877 memset(&m, 0, sizeof(m));
1878 m.pointer_vertex = vertex3f;
1879 m.tex[0] = R_GetTexture(basetexture);
1880 m.pointer_texcoord[0] = texcoord2f;
1883 m.texcubemap[1] = R_GetTexture(lightcubemap);
1885 m.pointer_texcoord3f[1] = vertex3f;
1886 m.texmatrix[1] = *matrix_modeltolight;
1888 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1889 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1892 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1894 // this final code is shared
1896 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1897 VectorScale(lightcolorbase, colorscale, color2);
1898 GL_LockArrays(firstvertex, numvertices);
1899 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1901 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1902 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1904 c_rt_lighttris += numtriangles;
1906 GL_LockArrays(0, 0);
1911 colorscale = diffusescale;
1912 // colorscale accounts for how much we multiply the brightness
1915 // mult is how many times the final pass of the lighting will be
1916 // performed to get more brightness than otherwise possible.
1918 // Limit mult to 64 for sanity sake.
1919 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1921 // 3/2 3D combine path (Geforce3, Radeon 8500)
1922 memset(&m, 0, sizeof(m));
1923 m.pointer_vertex = vertex3f;
1924 m.tex[0] = R_GetTexture(bumptexture);
1925 m.texcombinergb[0] = GL_REPLACE;
1926 m.pointer_texcoord[0] = texcoord2f;
1927 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1928 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1929 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1930 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1931 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1933 m.pointer_texcoord3f[2] = vertex3f;
1934 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1936 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1937 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1940 GL_ColorMask(0,0,0,1);
1941 GL_BlendFunc(GL_ONE, GL_ZERO);
1942 GL_LockArrays(firstvertex, numvertices);
1943 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1944 GL_LockArrays(0, 0);
1946 c_rt_lighttris += numtriangles;
1948 memset(&m, 0, sizeof(m));
1949 m.pointer_vertex = vertex3f;
1950 m.tex[0] = R_GetTexture(basetexture);
1951 m.pointer_texcoord[0] = texcoord2f;
1954 m.texcubemap[1] = R_GetTexture(lightcubemap);
1956 m.pointer_texcoord3f[1] = vertex3f;
1957 m.texmatrix[1] = *matrix_modeltolight;
1959 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1960 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1963 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1965 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1967 // 1/2/2 3D combine path (original Radeon)
1968 memset(&m, 0, sizeof(m));
1969 m.pointer_vertex = vertex3f;
1970 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1972 m.pointer_texcoord3f[0] = vertex3f;
1973 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1975 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1976 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1979 GL_ColorMask(0,0,0,1);
1980 GL_BlendFunc(GL_ONE, GL_ZERO);
1981 GL_LockArrays(firstvertex, numvertices);
1982 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1983 GL_LockArrays(0, 0);
1985 c_rt_lighttris += numtriangles;
1987 memset(&m, 0, sizeof(m));
1988 m.pointer_vertex = vertex3f;
1989 m.tex[0] = R_GetTexture(bumptexture);
1990 m.texcombinergb[0] = GL_REPLACE;
1991 m.pointer_texcoord[0] = texcoord2f;
1992 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1993 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1994 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1995 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1997 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1998 GL_LockArrays(firstvertex, numvertices);
1999 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2000 GL_LockArrays(0, 0);
2002 c_rt_lighttris += numtriangles;
2004 memset(&m, 0, sizeof(m));
2005 m.pointer_vertex = vertex3f;
2006 m.tex[0] = R_GetTexture(basetexture);
2007 m.pointer_texcoord[0] = texcoord2f;
2010 m.texcubemap[1] = R_GetTexture(lightcubemap);
2012 m.pointer_texcoord3f[1] = vertex3f;
2013 m.texmatrix[1] = *matrix_modeltolight;
2015 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2016 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2019 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2021 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
2023 // 2/2 3D combine path (original Radeon)
2024 memset(&m, 0, sizeof(m));
2025 m.pointer_vertex = vertex3f;
2026 m.tex[0] = R_GetTexture(bumptexture);
2027 m.texcombinergb[0] = GL_REPLACE;
2028 m.pointer_texcoord[0] = texcoord2f;
2029 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2030 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2031 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2032 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2034 GL_ColorMask(0,0,0,1);
2035 GL_BlendFunc(GL_ONE, GL_ZERO);
2036 GL_LockArrays(firstvertex, numvertices);
2037 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2038 GL_LockArrays(0, 0);
2040 c_rt_lighttris += numtriangles;
2042 memset(&m, 0, sizeof(m));
2043 m.pointer_vertex = vertex3f;
2044 m.tex[0] = R_GetTexture(basetexture);
2045 m.pointer_texcoord[0] = texcoord2f;
2046 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2048 m.pointer_texcoord3f[1] = vertex3f;
2049 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2051 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2052 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2054 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2056 else if (r_textureunits.integer >= 4)
2058 // 4/2 2D combine path (Geforce3, Radeon 8500)
2059 memset(&m, 0, sizeof(m));
2060 m.pointer_vertex = vertex3f;
2061 m.tex[0] = R_GetTexture(bumptexture);
2062 m.texcombinergb[0] = GL_REPLACE;
2063 m.pointer_texcoord[0] = texcoord2f;
2064 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2065 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2066 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2067 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2068 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2070 m.pointer_texcoord3f[2] = vertex3f;
2071 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2073 m.pointer_texcoord[2] = varray_texcoord2f[2];
2074 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2076 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2078 m.pointer_texcoord3f[3] = vertex3f;
2079 m.texmatrix[3] = *matrix_modeltoattenuationz;
2081 m.pointer_texcoord[3] = varray_texcoord2f[3];
2082 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2085 GL_ColorMask(0,0,0,1);
2086 GL_BlendFunc(GL_ONE, GL_ZERO);
2087 GL_LockArrays(firstvertex, numvertices);
2088 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2089 GL_LockArrays(0, 0);
2091 c_rt_lighttris += numtriangles;
2093 memset(&m, 0, sizeof(m));
2094 m.pointer_vertex = vertex3f;
2095 m.tex[0] = R_GetTexture(basetexture);
2096 m.pointer_texcoord[0] = texcoord2f;
2099 m.texcubemap[1] = R_GetTexture(lightcubemap);
2101 m.pointer_texcoord3f[1] = vertex3f;
2102 m.texmatrix[1] = *matrix_modeltolight;
2104 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2105 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2108 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2112 // 2/2/2 2D combine path (any dot3 card)
2113 memset(&m, 0, sizeof(m));
2114 m.pointer_vertex = vertex3f;
2115 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2117 m.pointer_texcoord3f[0] = vertex3f;
2118 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2120 m.pointer_texcoord[0] = varray_texcoord2f[0];
2121 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2123 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2125 m.pointer_texcoord3f[1] = vertex3f;
2126 m.texmatrix[1] = *matrix_modeltoattenuationz;
2128 m.pointer_texcoord[1] = varray_texcoord2f[1];
2129 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2132 GL_ColorMask(0,0,0,1);
2133 GL_BlendFunc(GL_ONE, GL_ZERO);
2134 GL_LockArrays(firstvertex, numvertices);
2135 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2136 GL_LockArrays(0, 0);
2138 c_rt_lighttris += numtriangles;
2140 memset(&m, 0, sizeof(m));
2141 m.pointer_vertex = vertex3f;
2142 m.tex[0] = R_GetTexture(bumptexture);
2143 m.texcombinergb[0] = GL_REPLACE;
2144 m.pointer_texcoord[0] = texcoord2f;
2145 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2146 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2147 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2148 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2150 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2151 GL_LockArrays(firstvertex, numvertices);
2152 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2153 GL_LockArrays(0, 0);
2155 c_rt_lighttris += numtriangles;
2157 memset(&m, 0, sizeof(m));
2158 m.pointer_vertex = vertex3f;
2159 m.tex[0] = R_GetTexture(basetexture);
2160 m.pointer_texcoord[0] = texcoord2f;
2163 m.texcubemap[1] = R_GetTexture(lightcubemap);
2165 m.pointer_texcoord3f[1] = vertex3f;
2166 m.texmatrix[1] = *matrix_modeltolight;
2168 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2169 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2172 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2174 // this final code is shared
2176 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2177 VectorScale(lightcolorbase, colorscale, color2);
2178 GL_LockArrays(firstvertex, numvertices);
2179 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2181 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2182 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2184 c_rt_lighttris += numtriangles;
2186 GL_LockArrays(0, 0);
2188 if (specularscale && glosstexture != r_texture_black)
2190 // FIXME: detect blendsquare!
2191 //if (gl_support_blendsquare)
2193 colorscale = specularscale;
2195 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2197 // 2/0/0/1/2 3D combine blendsquare path
2198 memset(&m, 0, sizeof(m));
2199 m.pointer_vertex = vertex3f;
2200 m.tex[0] = R_GetTexture(bumptexture);
2201 m.pointer_texcoord[0] = texcoord2f;
2202 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2203 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2204 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2205 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);
2207 GL_ColorMask(0,0,0,1);
2208 // this squares the result
2209 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2210 GL_LockArrays(firstvertex, numvertices);
2211 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2212 GL_LockArrays(0, 0);
2214 c_rt_lighttris += numtriangles;
2216 memset(&m, 0, sizeof(m));
2217 m.pointer_vertex = vertex3f;
2219 GL_LockArrays(firstvertex, numvertices);
2220 // square alpha in framebuffer a few times to make it shiny
2221 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2222 // these comments are a test run through this math for intensity 0.5
2223 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2224 // 0.25 * 0.25 = 0.0625 (this is another pass)
2225 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2226 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2228 c_rt_lighttris += numtriangles;
2229 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2231 c_rt_lighttris += numtriangles;
2232 GL_LockArrays(0, 0);
2234 memset(&m, 0, sizeof(m));
2235 m.pointer_vertex = vertex3f;
2236 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2238 m.pointer_texcoord3f[0] = vertex3f;
2239 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2241 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2242 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2245 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2246 GL_LockArrays(firstvertex, numvertices);
2247 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2248 GL_LockArrays(0, 0);
2250 c_rt_lighttris += numtriangles;
2252 memset(&m, 0, sizeof(m));
2253 m.pointer_vertex = vertex3f;
2254 m.tex[0] = R_GetTexture(glosstexture);
2255 m.pointer_texcoord[0] = texcoord2f;
2258 m.texcubemap[1] = R_GetTexture(lightcubemap);
2260 m.pointer_texcoord3f[1] = vertex3f;
2261 m.texmatrix[1] = *matrix_modeltolight;
2263 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2264 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2267 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2269 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2271 // 2/0/0/2 3D combine blendsquare path
2272 memset(&m, 0, sizeof(m));
2273 m.pointer_vertex = vertex3f;
2274 m.tex[0] = R_GetTexture(bumptexture);
2275 m.pointer_texcoord[0] = texcoord2f;
2276 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2277 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2278 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2279 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);
2281 GL_ColorMask(0,0,0,1);
2282 // this squares the result
2283 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2284 GL_LockArrays(firstvertex, numvertices);
2285 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2286 GL_LockArrays(0, 0);
2288 c_rt_lighttris += numtriangles;
2290 memset(&m, 0, sizeof(m));
2291 m.pointer_vertex = vertex3f;
2293 GL_LockArrays(firstvertex, numvertices);
2294 // square alpha in framebuffer a few times to make it shiny
2295 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2296 // these comments are a test run through this math for intensity 0.5
2297 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2298 // 0.25 * 0.25 = 0.0625 (this is another pass)
2299 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2300 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2302 c_rt_lighttris += numtriangles;
2303 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2305 c_rt_lighttris += numtriangles;
2306 GL_LockArrays(0, 0);
2308 memset(&m, 0, sizeof(m));
2309 m.pointer_vertex = vertex3f;
2310 m.tex[0] = R_GetTexture(glosstexture);
2311 m.pointer_texcoord[0] = texcoord2f;
2312 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2314 m.pointer_texcoord3f[1] = vertex3f;
2315 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2317 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2318 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2320 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2324 // 2/0/0/2/2 2D combine blendsquare path
2325 memset(&m, 0, sizeof(m));
2326 m.pointer_vertex = vertex3f;
2327 m.tex[0] = R_GetTexture(bumptexture);
2328 m.pointer_texcoord[0] = texcoord2f;
2329 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2330 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2331 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2332 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);
2334 GL_ColorMask(0,0,0,1);
2335 // this squares the result
2336 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2337 GL_LockArrays(firstvertex, numvertices);
2338 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2339 GL_LockArrays(0, 0);
2341 c_rt_lighttris += numtriangles;
2343 memset(&m, 0, sizeof(m));
2344 m.pointer_vertex = vertex3f;
2346 GL_LockArrays(firstvertex, numvertices);
2347 // square alpha in framebuffer a few times to make it shiny
2348 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2349 // these comments are a test run through this math for intensity 0.5
2350 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2351 // 0.25 * 0.25 = 0.0625 (this is another pass)
2352 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2353 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2355 c_rt_lighttris += numtriangles;
2356 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2358 c_rt_lighttris += numtriangles;
2359 GL_LockArrays(0, 0);
2361 memset(&m, 0, sizeof(m));
2362 m.pointer_vertex = vertex3f;
2363 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2365 m.pointer_texcoord3f[0] = vertex3f;
2366 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2368 m.pointer_texcoord[0] = varray_texcoord2f[0];
2369 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2371 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2373 m.pointer_texcoord3f[1] = vertex3f;
2374 m.texmatrix[1] = *matrix_modeltoattenuationz;
2376 m.pointer_texcoord[1] = varray_texcoord2f[1];
2377 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2380 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2381 GL_LockArrays(firstvertex, numvertices);
2382 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2383 GL_LockArrays(0, 0);
2385 c_rt_lighttris += numtriangles;
2387 memset(&m, 0, sizeof(m));
2388 m.pointer_vertex = vertex3f;
2389 m.tex[0] = R_GetTexture(glosstexture);
2390 m.pointer_texcoord[0] = texcoord2f;
2393 m.texcubemap[1] = R_GetTexture(lightcubemap);
2395 m.pointer_texcoord3f[1] = vertex3f;
2396 m.texmatrix[1] = *matrix_modeltolight;
2398 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2399 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2402 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2405 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2406 VectorScale(lightcolorbase, colorscale, color2);
2407 GL_LockArrays(firstvertex, numvertices);
2408 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2410 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2411 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2413 c_rt_lighttris += numtriangles;
2415 GL_LockArrays(0, 0);
2421 // TODO: add direct pants/shirt rendering
2422 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2423 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);
2424 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2425 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);
2428 GL_BlendFunc(GL_ONE, GL_ONE);
2429 VectorScale(lightcolorbase, ambientscale, color2);
2430 memset(&m, 0, sizeof(m));
2431 m.pointer_vertex = vertex3f;
2432 m.tex[0] = R_GetTexture(basetexture);
2433 m.pointer_texcoord[0] = texcoord2f;
2434 if (r_textureunits.integer >= 2)
2437 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2439 m.pointer_texcoord3f[1] = vertex3f;
2440 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2442 m.pointer_texcoord[1] = varray_texcoord2f[1];
2443 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2445 if (r_textureunits.integer >= 3)
2447 // Geforce3/Radeon class but not using dot3
2448 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2450 m.pointer_texcoord3f[2] = vertex3f;
2451 m.texmatrix[2] = *matrix_modeltoattenuationz;
2453 m.pointer_texcoord[2] = varray_texcoord2f[2];
2454 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2458 if (r_textureunits.integer >= 3)
2459 m.pointer_color = NULL;
2461 m.pointer_color = varray_color4f;
2463 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2465 color[0] = bound(0, color2[0], 1);
2466 color[1] = bound(0, color2[1], 1);
2467 color[2] = bound(0, color2[2], 1);
2468 if (r_textureunits.integer >= 3)
2469 GL_Color(color[0], color[1], color[2], 1);
2470 else if (r_textureunits.integer >= 2)
2471 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2473 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2474 GL_LockArrays(firstvertex, numvertices);
2475 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2476 GL_LockArrays(0, 0);
2478 c_rt_lighttris += numtriangles;
2483 GL_BlendFunc(GL_ONE, GL_ONE);
2484 VectorScale(lightcolorbase, diffusescale, color2);
2485 memset(&m, 0, sizeof(m));
2486 m.pointer_vertex = vertex3f;
2487 m.pointer_color = varray_color4f;
2488 m.tex[0] = R_GetTexture(basetexture);
2489 m.pointer_texcoord[0] = texcoord2f;
2490 if (r_textureunits.integer >= 2)
2493 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2495 m.pointer_texcoord3f[1] = vertex3f;
2496 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2498 m.pointer_texcoord[1] = varray_texcoord2f[1];
2499 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2501 if (r_textureunits.integer >= 3)
2503 // Geforce3/Radeon class but not using dot3
2504 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2506 m.pointer_texcoord3f[2] = vertex3f;
2507 m.texmatrix[2] = *matrix_modeltoattenuationz;
2509 m.pointer_texcoord[2] = varray_texcoord2f[2];
2510 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2515 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2517 color[0] = bound(0, color2[0], 1);
2518 color[1] = bound(0, color2[1], 1);
2519 color[2] = bound(0, color2[2], 1);
2520 if (r_textureunits.integer >= 3)
2521 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2522 else if (r_textureunits.integer >= 2)
2523 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2525 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2526 GL_LockArrays(firstvertex, numvertices);
2527 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2528 GL_LockArrays(0, 0);
2530 c_rt_lighttris += numtriangles;
2536 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2540 R_RTLight_Uncompile(rtlight);
2541 memset(rtlight, 0, sizeof(*rtlight));
2543 VectorCopy(light->origin, rtlight->shadoworigin);
2544 VectorCopy(light->color, rtlight->color);
2545 rtlight->radius = light->radius;
2546 //rtlight->cullradius = rtlight->radius;
2547 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2548 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2549 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2550 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2551 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2552 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2553 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2554 rtlight->cubemapname[0] = 0;
2555 if (light->cubemapname[0])
2556 strcpy(rtlight->cubemapname, light->cubemapname);
2557 else if (light->cubemapnum > 0)
2558 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2559 rtlight->shadow = light->shadow;
2560 rtlight->corona = light->corona;
2561 rtlight->style = light->style;
2562 rtlight->isstatic = isstatic;
2563 rtlight->coronasizescale = light->coronasizescale;
2564 rtlight->ambientscale = light->ambientscale;
2565 rtlight->diffusescale = light->diffusescale;
2566 rtlight->specularscale = light->specularscale;
2567 rtlight->flags = light->flags;
2568 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2569 // ConcatScale won't work here because this needs to scale rotate and
2570 // translate, not just rotate
2571 scale = 1.0f / rtlight->radius;
2572 for (k = 0;k < 3;k++)
2573 for (j = 0;j < 4;j++)
2574 rtlight->matrix_worldtolight.m[k][j] *= scale;
2575 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2576 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2578 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2579 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2580 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2581 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2584 // compiles rtlight geometry
2585 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2586 void R_RTLight_Compile(rtlight_t *rtlight)
2588 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2589 entity_render_t *ent = r_refdef.worldentity;
2590 model_t *model = r_refdef.worldmodel;
2593 // compile the light
2594 rtlight->compiled = true;
2595 rtlight->static_numleafs = 0;
2596 rtlight->static_numleafpvsbytes = 0;
2597 rtlight->static_leaflist = NULL;
2598 rtlight->static_leafpvs = NULL;
2599 rtlight->static_numsurfaces = 0;
2600 rtlight->static_surfacelist = NULL;
2601 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2602 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2603 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2604 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2605 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2606 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2608 if (model && model->GetLightInfo)
2610 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2611 r_shadow_compilingrtlight = rtlight;
2612 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->brush.num_surfaces);
2613 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);
2614 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2615 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2616 rtlight->static_numleafs = numleafs;
2617 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2618 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2619 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2620 rtlight->static_numsurfaces = numsurfaces;
2621 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2623 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2624 if (numleafpvsbytes)
2625 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2627 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2628 if (model->DrawShadowVolume && rtlight->shadow)
2630 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2631 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2632 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2634 if (model->DrawLight)
2636 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2637 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);
2638 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2640 // switch back to rendering when DrawShadowVolume or DrawLight is called
2641 r_shadow_compilingrtlight = NULL;
2645 // use smallest available cullradius - box radius or light radius
2646 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2647 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2651 if (rtlight->static_meshchain_shadow)
2654 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2657 shadowtris += mesh->numtriangles;
2663 if (rtlight->static_meshchain_light)
2666 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2669 lighttris += mesh->numtriangles;
2673 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);
2676 void R_RTLight_Uncompile(rtlight_t *rtlight)
2678 if (rtlight->compiled)
2680 if (rtlight->static_meshchain_shadow)
2681 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2682 rtlight->static_meshchain_shadow = NULL;
2683 if (rtlight->static_meshchain_light)
2684 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2685 rtlight->static_meshchain_light = NULL;
2686 // these allocations are grouped
2687 if (rtlight->static_leaflist)
2688 Mem_Free(rtlight->static_leaflist);
2689 rtlight->static_numleafs = 0;
2690 rtlight->static_numleafpvsbytes = 0;
2691 rtlight->static_leaflist = NULL;
2692 rtlight->static_leafpvs = NULL;
2693 rtlight->static_numsurfaces = 0;
2694 rtlight->static_surfacelist = NULL;
2695 rtlight->compiled = false;
2699 void R_Shadow_UncompileWorldLights(void)
2702 for (light = r_shadow_worldlightchain;light;light = light->next)
2703 R_RTLight_Uncompile(&light->rtlight);
2706 void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
2708 int i, shadow, usestencil;
2709 entity_render_t *ent;
2711 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2712 rtexture_t *cubemaptexture;
2713 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2714 int numleafs, numsurfaces;
2715 int *leaflist, *surfacelist;
2717 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2721 // skip lights that don't light (corona only lights)
2722 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2725 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2726 VectorScale(rtlight->color, f, lightcolor);
2727 if (VectorLength2(lightcolor) < 0.01)
2730 if (rtlight->selected)
2732 f = 2 + sin(realtime * M_PI * 4.0);
2733 VectorScale(lightcolor, f, lightcolor);
2737 // loading is done before visibility checks because loading should happen
2738 // all at once at the start of a level, not when it stalls gameplay.
2739 // (especially important to benchmarks)
2740 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2741 R_RTLight_Compile(rtlight);
2742 if (rtlight->cubemapname[0])
2743 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2745 cubemaptexture = NULL;
2747 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2748 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2749 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2750 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2751 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2752 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2753 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2760 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2762 // compiled light, world available and can receive realtime lighting
2763 // retrieve leaf information
2764 numleafs = rtlight->static_numleafs;
2765 leaflist = rtlight->static_leaflist;
2766 leafpvs = rtlight->static_leafpvs;
2767 numsurfaces = rtlight->static_numsurfaces;
2768 surfacelist = rtlight->static_surfacelist;
2769 VectorCopy(rtlight->cullmins, cullmins);
2770 VectorCopy(rtlight->cullmaxs, cullmaxs);
2772 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2774 // dynamic light, world available and can receive realtime lighting
2775 // if the light box is offscreen, skip it right away
2776 if (R_CullBox(cullmins, cullmaxs))
2778 // calculate lit surfaces and leafs
2779 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
2780 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);
2781 leaflist = r_shadow_buffer_leaflist;
2782 leafpvs = r_shadow_buffer_leafpvs;
2783 surfacelist = r_shadow_buffer_surfacelist;
2785 // if the reduced leaf bounds are offscreen, skip it
2786 if (R_CullBox(cullmins, cullmaxs))
2788 // check if light is illuminating any visible leafs
2791 for (i = 0;i < numleafs;i++)
2792 if (r_worldleafvisible[leaflist[i]])
2797 // set up a scissor rectangle for this light
2798 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2803 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2806 if (shadow && ((gl_stencil && !visiblelighting) || visiblevolumes))
2810 qglDisable(GL_CULL_FACE);
2811 GL_DepthTest(visiblevolumes < 2);
2812 GL_Color(0.0, 0.0125, 0.1, 1);
2816 R_Shadow_Stage_ShadowVolumes();
2817 GL_Clear(GL_STENCIL_BUFFER_BIT);
2821 ent = r_refdef.worldentity;
2822 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2824 memset(&m, 0, sizeof(m));
2825 R_Mesh_Matrix(&ent->matrix);
2826 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2828 m.pointer_vertex = mesh->vertex3f;
2830 GL_LockArrays(0, mesh->numverts);
2831 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2833 // increment stencil if backface is behind depthbuffer
2834 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2835 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2836 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2837 c_rtcached_shadowmeshes++;
2838 c_rtcached_shadowtris += mesh->numtriangles;
2839 // decrement stencil if frontface is behind depthbuffer
2840 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2841 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2843 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2844 c_rtcached_shadowmeshes++;
2845 c_rtcached_shadowtris += mesh->numtriangles;
2846 GL_LockArrays(0, 0);
2849 else if (numsurfaces)
2851 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2852 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2854 if (r_drawentities.integer)
2856 for (i = 0;i < r_refdef.numentities;i++)
2858 ent = r_refdef.entities[i];
2860 if (r_shadow_cull.integer)
2862 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2864 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingLeafPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2867 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2869 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2870 // light emitting entities should not cast their own shadow
2871 if (VectorLength2(relativelightorigin) < 0.1)
2873 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2874 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2875 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2876 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2877 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2878 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2879 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2884 if (visiblelighting || !visiblevolumes)
2886 if (visiblelighting)
2888 qglEnable(GL_CULL_FACE);
2889 GL_DepthTest(visiblelighting < 2);
2890 GL_Color(0.1, 0.0125, 0, 1);
2893 R_Shadow_Stage_Light(usestencil);
2895 ent = r_refdef.worldentity;
2896 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2898 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2899 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2900 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2901 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2902 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2903 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2904 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2905 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2906 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2908 R_Mesh_Matrix(&ent->matrix);
2909 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2910 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);
2913 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);
2915 if (r_drawentities.integer)
2917 for (i = 0;i < r_refdef.numentities;i++)
2919 ent = r_refdef.entities[i];
2920 // can't draw transparent entity lighting here because
2921 // transparent meshes are deferred for later
2922 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)
2924 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2925 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2926 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2927 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2928 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2929 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2930 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2931 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2932 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);
2939 void R_ShadowVolumeLighting(int visiblelighting, int visiblevolumes)
2945 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2946 R_Shadow_EditLights_Reload_f();
2948 if (visiblelighting || visiblevolumes)
2950 memset(&m, 0, sizeof(m));
2953 GL_BlendFunc(GL_ONE, GL_ONE);
2954 GL_DepthMask(false);
2955 qglCullFace(GL_FRONT); // this culls back
2958 R_Shadow_Stage_Begin();
2959 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2960 if (r_shadow_debuglight.integer >= 0)
2962 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2963 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2964 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
2967 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2968 if (light->flags & flag)
2969 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
2971 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2972 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
2974 if (visiblelighting || visiblevolumes)
2976 qglEnable(GL_CULL_FACE);
2977 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2980 R_Shadow_Stage_End();
2983 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2984 typedef struct suffixinfo_s
2987 qboolean flipx, flipy, flipdiagonal;
2990 static suffixinfo_t suffix[3][6] =
2993 {"px", false, false, false},
2994 {"nx", false, false, false},
2995 {"py", false, false, false},
2996 {"ny", false, false, false},
2997 {"pz", false, false, false},
2998 {"nz", false, false, false}
3001 {"posx", false, false, false},
3002 {"negx", false, false, false},
3003 {"posy", false, false, false},
3004 {"negy", false, false, false},
3005 {"posz", false, false, false},
3006 {"negz", false, false, false}
3009 {"rt", true, false, true},
3010 {"lf", false, true, true},
3011 {"ft", true, true, false},
3012 {"bk", false, false, false},
3013 {"up", true, false, true},
3014 {"dn", true, false, true}
3018 static int componentorder[4] = {0, 1, 2, 3};
3020 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3022 int i, j, cubemapsize;
3023 qbyte *cubemappixels, *image_rgba;
3024 rtexture_t *cubemaptexture;
3026 // must start 0 so the first loadimagepixels has no requested width/height
3028 cubemappixels = NULL;
3029 cubemaptexture = NULL;
3030 // keep trying different suffix groups (posx, px, rt) until one loads
3031 for (j = 0;j < 3 && !cubemappixels;j++)
3033 // load the 6 images in the suffix group
3034 for (i = 0;i < 6;i++)
3036 // generate an image name based on the base and and suffix
3037 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3039 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3041 // an image loaded, make sure width and height are equal
3042 if (image_width == image_height)
3044 // if this is the first image to load successfully, allocate the cubemap memory
3045 if (!cubemappixels && image_width >= 1)
3047 cubemapsize = image_width;
3048 // note this clears to black, so unavailable sides are black
3049 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3051 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3053 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);
3056 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3058 Mem_Free(image_rgba);
3062 // if a cubemap loaded, upload it
3065 if (!r_shadow_filters_texturepool)
3066 r_shadow_filters_texturepool = R_AllocTexturePool();
3067 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3068 Mem_Free(cubemappixels);
3072 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3073 for (j = 0;j < 3;j++)
3074 for (i = 0;i < 6;i++)
3075 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3076 Con_Print(" and was unable to find any of them.\n");
3078 return cubemaptexture;
3081 rtexture_t *R_Shadow_Cubemap(const char *basename)
3084 for (i = 0;i < numcubemaps;i++)
3085 if (!strcasecmp(cubemaps[i].basename, basename))
3086 return cubemaps[i].texture;
3087 if (i >= MAX_CUBEMAPS)
3090 strcpy(cubemaps[i].basename, basename);
3091 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3092 return cubemaps[i].texture;
3095 void R_Shadow_FreeCubemaps(void)
3098 R_FreeTexturePool(&r_shadow_filters_texturepool);
3101 dlight_t *R_Shadow_NewWorldLight(void)
3104 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3105 light->next = r_shadow_worldlightchain;
3106 r_shadow_worldlightchain = light;
3110 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)
3112 VectorCopy(origin, light->origin);
3113 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3114 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3115 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3116 light->color[0] = max(color[0], 0);
3117 light->color[1] = max(color[1], 0);
3118 light->color[2] = max(color[2], 0);
3119 light->radius = max(radius, 0);
3120 light->style = style;
3121 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3123 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3126 light->shadow = shadowenable;
3127 light->corona = corona;
3130 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3131 light->coronasizescale = coronasizescale;
3132 light->ambientscale = ambientscale;
3133 light->diffusescale = diffusescale;
3134 light->specularscale = specularscale;
3135 light->flags = flags;
3136 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3138 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3141 void R_Shadow_FreeWorldLight(dlight_t *light)
3143 dlight_t **lightpointer;
3144 R_RTLight_Uncompile(&light->rtlight);
3145 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3146 if (*lightpointer != light)
3147 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3148 *lightpointer = light->next;
3152 void R_Shadow_ClearWorldLights(void)
3154 while (r_shadow_worldlightchain)
3155 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3156 r_shadow_selectedlight = NULL;
3157 R_Shadow_FreeCubemaps();
3160 void R_Shadow_SelectLight(dlight_t *light)
3162 if (r_shadow_selectedlight)
3163 r_shadow_selectedlight->selected = false;
3164 r_shadow_selectedlight = light;
3165 if (r_shadow_selectedlight)
3166 r_shadow_selectedlight->selected = true;
3169 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3171 float scale = r_editlights_cursorgrid.value * 0.5f;
3172 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);
3175 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3178 const dlight_t *light;
3181 if (light->selected)
3182 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3185 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);
3188 void R_Shadow_DrawLightSprites(void)
3194 for (i = 0;i < 5;i++)
3196 lighttextures[i] = NULL;
3197 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3198 lighttextures[i] = pic->tex;
3201 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3202 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3203 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3206 void R_Shadow_SelectLightInView(void)
3208 float bestrating, rating, temp[3];
3209 dlight_t *best, *light;
3212 for (light = r_shadow_worldlightchain;light;light = light->next)
3214 VectorSubtract(light->origin, r_vieworigin, temp);
3215 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3218 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3219 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3221 bestrating = rating;
3226 R_Shadow_SelectLight(best);
3229 void R_Shadow_LoadWorldLights(void)
3231 int n, a, style, shadow, flags;
3232 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3233 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3234 if (r_refdef.worldmodel == NULL)
3236 Con_Print("No map loaded.\n");
3239 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3240 strlcat (name, ".rtlights", sizeof (name));
3241 lightsstring = FS_LoadFile(name, tempmempool, false);
3251 for (;COM_Parse(t, true) && strcmp(
3252 if (COM_Parse(t, true))
3254 if (com_token[0] == '!')
3257 origin[0] = atof(com_token+1);
3260 origin[0] = atof(com_token);
3265 while (*s && *s != '\n' && *s != '\r')
3271 // check for modifier flags
3278 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);
3281 flags = LIGHTFLAG_REALTIMEMODE;
3289 coronasizescale = 0.25f;
3291 VectorClear(angles);
3294 if (a < 9 || !strcmp(cubemapname, "\"\""))
3296 // remove quotes on cubemapname
3297 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3299 cubemapname[strlen(cubemapname)-1] = 0;
3300 strcpy(cubemapname, cubemapname + 1);
3304 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);
3307 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3308 radius *= r_editlights_rtlightssizescale.value;
3309 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3317 Con_Printf("invalid rtlights file \"%s\"\n", name);
3318 Mem_Free(lightsstring);
3322 void R_Shadow_SaveWorldLights(void)
3325 int bufchars, bufmaxchars;
3327 char name[MAX_QPATH];
3329 if (!r_shadow_worldlightchain)
3331 if (r_refdef.worldmodel == NULL)
3333 Con_Print("No map loaded.\n");
3336 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3337 strlcat (name, ".rtlights", sizeof (name));
3338 bufchars = bufmaxchars = 0;
3340 for (light = r_shadow_worldlightchain;light;light = light->next)
3342 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3343 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);
3344 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3345 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]);
3347 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);
3348 if (bufchars + (int) strlen(line) > bufmaxchars)
3350 bufmaxchars = bufchars + strlen(line) + 2048;
3352 buf = Mem_Alloc(tempmempool, bufmaxchars);
3356 memcpy(buf, oldbuf, bufchars);
3362 memcpy(buf + bufchars, line, strlen(line));
3363 bufchars += strlen(line);
3367 FS_WriteFile(name, buf, bufchars);
3372 void R_Shadow_LoadLightsFile(void)
3375 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3376 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3377 if (r_refdef.worldmodel == NULL)
3379 Con_Print("No map loaded.\n");
3382 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3383 strlcat (name, ".lights", sizeof (name));
3384 lightsstring = FS_LoadFile(name, tempmempool, false);
3392 while (*s && *s != '\n' && *s != '\r')
3398 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);
3402 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);
3405 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3406 radius = bound(15, radius, 4096);
3407 VectorScale(color, (2.0f / (8388608.0f)), color);
3408 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3416 Con_Printf("invalid lights file \"%s\"\n", name);
3417 Mem_Free(lightsstring);
3421 // tyrlite/hmap2 light types in the delay field
3422 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3424 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3426 int entnum, style, islight, skin, pflags, effects, type, n;
3429 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3430 char key[256], value[1024];
3432 if (r_refdef.worldmodel == NULL)
3434 Con_Print("No map loaded.\n");
3437 // try to load a .ent file first
3438 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3439 strlcat (key, ".ent", sizeof (key));
3440 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3441 // and if that is not found, fall back to the bsp file entity string
3443 data = r_refdef.worldmodel->brush.entities;
3446 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3448 type = LIGHTTYPE_MINUSX;
3449 origin[0] = origin[1] = origin[2] = 0;
3450 originhack[0] = originhack[1] = originhack[2] = 0;
3451 angles[0] = angles[1] = angles[2] = 0;
3452 color[0] = color[1] = color[2] = 1;
3453 light[0] = light[1] = light[2] = 1;light[3] = 300;
3454 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3464 if (!COM_ParseToken(&data, false))
3466 if (com_token[0] == '}')
3467 break; // end of entity
3468 if (com_token[0] == '_')
3469 strcpy(key, com_token + 1);
3471 strcpy(key, com_token);
3472 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3473 key[strlen(key)-1] = 0;
3474 if (!COM_ParseToken(&data, false))
3476 strcpy(value, com_token);
3478 // now that we have the key pair worked out...
3479 if (!strcmp("light", key))
3481 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3485 light[0] = vec[0] * (1.0f / 256.0f);
3486 light[1] = vec[0] * (1.0f / 256.0f);
3487 light[2] = vec[0] * (1.0f / 256.0f);
3493 light[0] = vec[0] * (1.0f / 255.0f);
3494 light[1] = vec[1] * (1.0f / 255.0f);
3495 light[2] = vec[2] * (1.0f / 255.0f);
3499 else if (!strcmp("delay", key))
3501 else if (!strcmp("origin", key))
3502 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3503 else if (!strcmp("angle", key))
3504 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3505 else if (!strcmp("angles", key))
3506 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3507 else if (!strcmp("color", key))
3508 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3509 else if (!strcmp("wait", key))
3510 fadescale = atof(value);
3511 else if (!strcmp("classname", key))
3513 if (!strncmp(value, "light", 5))
3516 if (!strcmp(value, "light_fluoro"))
3521 overridecolor[0] = 1;
3522 overridecolor[1] = 1;
3523 overridecolor[2] = 1;
3525 if (!strcmp(value, "light_fluorospark"))
3530 overridecolor[0] = 1;
3531 overridecolor[1] = 1;
3532 overridecolor[2] = 1;
3534 if (!strcmp(value, "light_globe"))
3539 overridecolor[0] = 1;
3540 overridecolor[1] = 0.8;
3541 overridecolor[2] = 0.4;
3543 if (!strcmp(value, "light_flame_large_yellow"))
3548 overridecolor[0] = 1;
3549 overridecolor[1] = 0.5;
3550 overridecolor[2] = 0.1;
3552 if (!strcmp(value, "light_flame_small_yellow"))
3557 overridecolor[0] = 1;
3558 overridecolor[1] = 0.5;
3559 overridecolor[2] = 0.1;
3561 if (!strcmp(value, "light_torch_small_white"))
3566 overridecolor[0] = 1;
3567 overridecolor[1] = 0.5;
3568 overridecolor[2] = 0.1;
3570 if (!strcmp(value, "light_torch_small_walltorch"))
3575 overridecolor[0] = 1;
3576 overridecolor[1] = 0.5;
3577 overridecolor[2] = 0.1;
3581 else if (!strcmp("style", key))
3582 style = atoi(value);
3583 else if (r_refdef.worldmodel->type == mod_brushq3)
3585 if (!strcmp("scale", key))
3586 lightscale = atof(value);
3587 if (!strcmp("fade", key))
3588 fadescale = atof(value);
3590 else if (!strcmp("skin", key))
3591 skin = (int)atof(value);
3592 else if (!strcmp("pflags", key))
3593 pflags = (int)atof(value);
3594 else if (!strcmp("effects", key))
3595 effects = (int)atof(value);
3599 if (lightscale <= 0)
3603 if (color[0] == color[1] && color[0] == color[2])
3605 color[0] *= overridecolor[0];
3606 color[1] *= overridecolor[1];
3607 color[2] *= overridecolor[2];
3609 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3610 color[0] = color[0] * light[0];
3611 color[1] = color[1] * light[1];
3612 color[2] = color[2] * light[2];
3615 case LIGHTTYPE_MINUSX:
3617 case LIGHTTYPE_RECIPX:
3619 VectorScale(color, (1.0f / 16.0f), color);
3621 case LIGHTTYPE_RECIPXX:
3623 VectorScale(color, (1.0f / 16.0f), color);
3626 case LIGHTTYPE_NONE:
3630 case LIGHTTYPE_MINUSXX:
3633 VectorAdd(origin, originhack, origin);
3635 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);
3638 Mem_Free(entfiledata);
3642 void R_Shadow_SetCursorLocationForView(void)
3645 vec3_t dest, endpos;
3647 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3648 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3649 if (trace.fraction < 1)
3651 dist = trace.fraction * r_editlights_cursordistance.value;
3652 push = r_editlights_cursorpushback.value;
3656 VectorMA(trace.endpos, push, r_viewforward, endpos);
3657 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3659 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3660 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3661 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3664 void R_Shadow_UpdateWorldLightSelection(void)
3666 if (r_editlights.integer)
3668 R_Shadow_SetCursorLocationForView();
3669 R_Shadow_SelectLightInView();
3670 R_Shadow_DrawLightSprites();
3673 R_Shadow_SelectLight(NULL);
3676 void R_Shadow_EditLights_Clear_f(void)
3678 R_Shadow_ClearWorldLights();
3681 void R_Shadow_EditLights_Reload_f(void)
3683 if (!r_refdef.worldmodel)
3685 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3686 R_Shadow_ClearWorldLights();
3687 R_Shadow_LoadWorldLights();
3688 if (r_shadow_worldlightchain == NULL)
3690 R_Shadow_LoadLightsFile();
3691 if (r_shadow_worldlightchain == NULL)
3692 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3696 void R_Shadow_EditLights_Save_f(void)
3698 if (!r_refdef.worldmodel)
3700 R_Shadow_SaveWorldLights();
3703 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3705 R_Shadow_ClearWorldLights();
3706 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3709 void R_Shadow_EditLights_ImportLightsFile_f(void)
3711 R_Shadow_ClearWorldLights();
3712 R_Shadow_LoadLightsFile();
3715 void R_Shadow_EditLights_Spawn_f(void)
3718 if (!r_editlights.integer)
3720 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3723 if (Cmd_Argc() != 1)
3725 Con_Print("r_editlights_spawn does not take parameters\n");
3728 color[0] = color[1] = color[2] = 1;
3729 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3732 void R_Shadow_EditLights_Edit_f(void)
3734 vec3_t origin, angles, color;
3735 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3736 int style, shadows, flags, normalmode, realtimemode;
3737 char cubemapname[1024];
3738 if (!r_editlights.integer)
3740 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3743 if (!r_shadow_selectedlight)
3745 Con_Print("No selected light.\n");
3748 VectorCopy(r_shadow_selectedlight->origin, origin);
3749 VectorCopy(r_shadow_selectedlight->angles, angles);
3750 VectorCopy(r_shadow_selectedlight->color, color);
3751 radius = r_shadow_selectedlight->radius;
3752 style = r_shadow_selectedlight->style;
3753 if (r_shadow_selectedlight->cubemapname)
3754 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3757 shadows = r_shadow_selectedlight->shadow;
3758 corona = r_shadow_selectedlight->corona;
3759 coronasizescale = r_shadow_selectedlight->coronasizescale;
3760 ambientscale = r_shadow_selectedlight->ambientscale;
3761 diffusescale = r_shadow_selectedlight->diffusescale;
3762 specularscale = r_shadow_selectedlight->specularscale;
3763 flags = r_shadow_selectedlight->flags;
3764 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3765 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3766 if (!strcmp(Cmd_Argv(1), "origin"))
3768 if (Cmd_Argc() != 5)
3770 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3773 origin[0] = atof(Cmd_Argv(2));
3774 origin[1] = atof(Cmd_Argv(3));
3775 origin[2] = atof(Cmd_Argv(4));
3777 else if (!strcmp(Cmd_Argv(1), "originx"))
3779 if (Cmd_Argc() != 3)
3781 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3784 origin[0] = atof(Cmd_Argv(2));
3786 else if (!strcmp(Cmd_Argv(1), "originy"))
3788 if (Cmd_Argc() != 3)
3790 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3793 origin[1] = atof(Cmd_Argv(2));
3795 else if (!strcmp(Cmd_Argv(1), "originz"))
3797 if (Cmd_Argc() != 3)
3799 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3802 origin[2] = atof(Cmd_Argv(2));
3804 else if (!strcmp(Cmd_Argv(1), "move"))
3806 if (Cmd_Argc() != 5)
3808 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3811 origin[0] += atof(Cmd_Argv(2));
3812 origin[1] += atof(Cmd_Argv(3));
3813 origin[2] += atof(Cmd_Argv(4));
3815 else if (!strcmp(Cmd_Argv(1), "movex"))
3817 if (Cmd_Argc() != 3)
3819 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3822 origin[0] += atof(Cmd_Argv(2));
3824 else if (!strcmp(Cmd_Argv(1), "movey"))
3826 if (Cmd_Argc() != 3)
3828 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3831 origin[1] += atof(Cmd_Argv(2));
3833 else if (!strcmp(Cmd_Argv(1), "movez"))
3835 if (Cmd_Argc() != 3)
3837 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3840 origin[2] += atof(Cmd_Argv(2));
3842 else if (!strcmp(Cmd_Argv(1), "angles"))
3844 if (Cmd_Argc() != 5)
3846 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3849 angles[0] = atof(Cmd_Argv(2));
3850 angles[1] = atof(Cmd_Argv(3));
3851 angles[2] = atof(Cmd_Argv(4));
3853 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3855 if (Cmd_Argc() != 3)
3857 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3860 angles[0] = atof(Cmd_Argv(2));
3862 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3864 if (Cmd_Argc() != 3)
3866 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3869 angles[1] = atof(Cmd_Argv(2));
3871 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3873 if (Cmd_Argc() != 3)
3875 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3878 angles[2] = atof(Cmd_Argv(2));
3880 else if (!strcmp(Cmd_Argv(1), "color"))
3882 if (Cmd_Argc() != 5)
3884 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3887 color[0] = atof(Cmd_Argv(2));
3888 color[1] = atof(Cmd_Argv(3));
3889 color[2] = atof(Cmd_Argv(4));
3891 else if (!strcmp(Cmd_Argv(1), "radius"))
3893 if (Cmd_Argc() != 3)
3895 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3898 radius = atof(Cmd_Argv(2));
3900 else if (!strcmp(Cmd_Argv(1), "style"))
3902 if (Cmd_Argc() != 3)
3904 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3907 style = atoi(Cmd_Argv(2));
3909 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3913 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3916 if (Cmd_Argc() == 3)
3917 strcpy(cubemapname, Cmd_Argv(2));
3921 else if (!strcmp(Cmd_Argv(1), "shadows"))
3923 if (Cmd_Argc() != 3)
3925 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3928 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3930 else if (!strcmp(Cmd_Argv(1), "corona"))
3932 if (Cmd_Argc() != 3)
3934 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3937 corona = atof(Cmd_Argv(2));
3939 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3941 if (Cmd_Argc() != 3)
3943 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3946 coronasizescale = atof(Cmd_Argv(2));
3948 else if (!strcmp(Cmd_Argv(1), "ambient"))
3950 if (Cmd_Argc() != 3)
3952 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3955 ambientscale = atof(Cmd_Argv(2));
3957 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3959 if (Cmd_Argc() != 3)
3961 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3964 diffusescale = atof(Cmd_Argv(2));
3966 else if (!strcmp(Cmd_Argv(1), "specular"))
3968 if (Cmd_Argc() != 3)
3970 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3973 specularscale = atof(Cmd_Argv(2));
3975 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3977 if (Cmd_Argc() != 3)
3979 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3982 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3984 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3986 if (Cmd_Argc() != 3)
3988 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3991 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3995 Con_Print("usage: r_editlights_edit [property] [value]\n");
3996 Con_Print("Selected light's properties:\n");
3997 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3998 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3999 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4000 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4001 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4002 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4003 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4004 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4005 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4006 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4007 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4008 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4009 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4010 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4013 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4014 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4017 void R_Shadow_EditLights_EditAll_f(void)
4021 if (!r_editlights.integer)
4023 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4027 for (light = r_shadow_worldlightchain;light;light = light->next)
4029 R_Shadow_SelectLight(light);
4030 R_Shadow_EditLights_Edit_f();
4034 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4036 int lightnumber, lightcount;
4040 if (!r_editlights.integer)
4046 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4047 if (light == r_shadow_selectedlight)
4048 lightnumber = lightcount;
4049 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;
4050 if (r_shadow_selectedlight == NULL)
4052 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4053 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;
4054 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;
4055 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;
4056 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4057 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4058 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4059 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;
4060 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4061 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4062 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4063 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4064 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4065 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;
4066 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;
4069 void R_Shadow_EditLights_ToggleShadow_f(void)
4071 if (!r_editlights.integer)
4073 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4076 if (!r_shadow_selectedlight)
4078 Con_Print("No selected light.\n");
4081 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);
4084 void R_Shadow_EditLights_ToggleCorona_f(void)
4086 if (!r_editlights.integer)
4088 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4091 if (!r_shadow_selectedlight)
4093 Con_Print("No selected light.\n");
4096 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);
4099 void R_Shadow_EditLights_Remove_f(void)
4101 if (!r_editlights.integer)
4103 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4106 if (!r_shadow_selectedlight)
4108 Con_Print("No selected light.\n");
4111 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4112 r_shadow_selectedlight = NULL;
4115 void R_Shadow_EditLights_Help_f(void)
4118 "Documentation on r_editlights system:\n"
4120 "r_editlights : enable/disable editing mode\n"
4121 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4122 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4123 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4124 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4125 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4126 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4127 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4129 "r_editlights_help : this help\n"
4130 "r_editlights_clear : remove all lights\n"
4131 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4132 "r_editlights_save : save to .rtlights file\n"
4133 "r_editlights_spawn : create a light with default settings\n"
4134 "r_editlights_edit command : edit selected light - more documentation below\n"
4135 "r_editlights_remove : remove selected light\n"
4136 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4137 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4138 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4140 "origin x y z : set light location\n"
4141 "originx x: set x component of light location\n"
4142 "originy y: set y component of light location\n"
4143 "originz z: set z component of light location\n"
4144 "move x y z : adjust light location\n"
4145 "movex x: adjust x component of light location\n"
4146 "movey y: adjust y component of light location\n"
4147 "movez z: adjust z component of light location\n"
4148 "angles x y z : set light angles\n"
4149 "anglesx x: set x component of light angles\n"
4150 "anglesy y: set y component of light angles\n"
4151 "anglesz z: set z component of light angles\n"
4152 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4153 "radius radius : set radius (size) of light\n"
4154 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4155 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4156 "shadows 1/0 : turn on/off shadows\n"
4157 "corona n : set corona intensity\n"
4158 "coronasize n : set corona size (0-1)\n"
4159 "ambient n : set ambient intensity (0-1)\n"
4160 "diffuse n : set diffuse intensity (0-1)\n"
4161 "specular n : set specular intensity (0-1)\n"
4162 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4163 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4164 "<nothing> : print light properties to console\n"
4168 void R_Shadow_EditLights_CopyInfo_f(void)
4170 if (!r_editlights.integer)
4172 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4175 if (!r_shadow_selectedlight)
4177 Con_Print("No selected light.\n");
4180 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4181 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4182 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4183 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4184 if (r_shadow_selectedlight->cubemapname)
4185 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4187 r_shadow_bufferlight.cubemapname[0] = 0;
4188 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4189 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4190 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4191 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4192 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4193 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4194 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4197 void R_Shadow_EditLights_PasteInfo_f(void)
4199 if (!r_editlights.integer)
4201 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4204 if (!r_shadow_selectedlight)
4206 Con_Print("No selected light.\n");
4209 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);
4212 void R_Shadow_EditLights_Init(void)
4214 Cvar_RegisterVariable(&r_editlights);
4215 Cvar_RegisterVariable(&r_editlights_cursordistance);
4216 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4217 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4218 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4219 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4220 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4221 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4222 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4223 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4224 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4225 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4226 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4227 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4228 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4229 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4230 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4231 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4232 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4233 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4234 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4235 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);