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 contains 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 typedef enum r_shadowstage_e
125 R_SHADOWSTAGE_STENCIL,
126 R_SHADOWSTAGE_STENCILTWOSIDE,
127 R_SHADOWSTAGE_LIGHT_VERTEX,
128 R_SHADOWSTAGE_LIGHT_DOT3,
129 R_SHADOWSTAGE_LIGHT_GLSL,
130 R_SHADOWSTAGE_VISIBLEVOLUMES,
131 R_SHADOWSTAGE_VISIBLELIGHTING,
135 r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
137 mempool_t *r_shadow_mempool;
139 int maxshadowelements;
153 int r_shadow_buffer_numleafpvsbytes;
154 qbyte *r_shadow_buffer_leafpvs;
155 int *r_shadow_buffer_leaflist;
157 int r_shadow_buffer_numsurfacepvsbytes;
158 qbyte *r_shadow_buffer_surfacepvs;
159 int *r_shadow_buffer_surfacelist;
161 rtexturepool_t *r_shadow_texturepool;
162 rtexture_t *r_shadow_attenuation2dtexture;
163 rtexture_t *r_shadow_attenuation3dtexture;
165 // lights are reloaded when this changes
166 char r_shadow_mapname[MAX_QPATH];
168 // used only for light filters (cubemaps)
169 rtexturepool_t *r_shadow_filters_texturepool;
171 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
172 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
173 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
174 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
175 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
176 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
177 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
178 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
179 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
180 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
181 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
182 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
183 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
184 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
185 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
186 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
187 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
188 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
189 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
190 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
191 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
192 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
193 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
194 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
195 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
196 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
197 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
198 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
199 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
200 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
201 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
202 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
203 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
204 cvar_t r_editlights = {0, "r_editlights", "0"};
205 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
206 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
207 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
208 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
209 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
210 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
211 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
213 float r_shadow_attenpower, r_shadow_attenscale;
215 rtlight_t *r_shadow_compilingrtlight;
216 dlight_t *r_shadow_worldlightchain;
217 dlight_t *r_shadow_selectedlight;
218 dlight_t r_shadow_bufferlight;
219 vec3_t r_editlights_cursorlocation;
221 rtexture_t *lighttextures[5];
223 extern int con_vislines;
225 typedef struct cubemapinfo_s
232 #define MAX_CUBEMAPS 256
233 static int numcubemaps;
234 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
236 #define SHADERPERMUTATION_SPECULAR (1<<0)
237 #define SHADERPERMUTATION_FOG (1<<1)
238 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
239 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
240 #define SHADERPERMUTATION_COUNT (1<<4)
242 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
244 void R_Shadow_UncompileWorldLights(void);
245 void R_Shadow_ClearWorldLights(void);
246 void R_Shadow_SaveWorldLights(void);
247 void R_Shadow_LoadWorldLights(void);
248 void R_Shadow_LoadLightsFile(void);
249 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
250 void R_Shadow_EditLights_Reload_f(void);
251 void R_Shadow_ValidateCvars(void);
252 static void R_Shadow_MakeTextures(void);
253 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
255 const char *builtinshader_light_vert =
256 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
257 "// written by Forest 'LordHavoc' Hale\n"
259 "uniform vec3 LightPosition;\n"
261 "varying vec2 TexCoord;\n"
262 "varying vec3 CubeVector;\n"
263 "varying vec3 LightVector;\n"
265 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
266 "uniform vec3 EyePosition;\n"
267 "varying vec3 EyeVector;\n"
270 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
274 " // copy the surface texcoord\n"
275 " TexCoord = gl_MultiTexCoord0.st;\n"
277 " // transform vertex position into light attenuation/cubemap space\n"
278 " // (-1 to +1 across the light box)\n"
279 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
281 " // transform unnormalized light direction into tangent space\n"
282 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
283 " // normalize it per pixel)\n"
284 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
285 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
286 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
287 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
289 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
290 " // transform unnormalized eye direction into tangent space\n"
291 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
292 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
293 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
294 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
297 " // transform vertex to camera space, using ftransform to match non-VS\n"
299 " gl_Position = ftransform();\n"
303 const char *builtinshader_light_frag =
304 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
305 "// written by Forest 'LordHavoc' Hale\n"
307 "uniform vec3 LightColor;\n"
309 "#ifdef USEOFFSETMAPPING\n"
310 "uniform float OffsetMapping_Scale;\n"
311 "uniform float OffsetMapping_Bias;\n"
313 "#ifdef USESPECULAR\n"
314 "uniform float SpecularPower;\n"
317 "uniform float FogRangeRecip;\n"
319 "uniform float AmbientScale;\n"
320 "uniform float DiffuseScale;\n"
321 "#ifdef USESPECULAR\n"
322 "uniform float SpecularScale;\n"
325 "uniform sampler2D Texture_Normal;\n"
326 "uniform sampler2D Texture_Color;\n"
327 "#ifdef USESPECULAR\n"
328 "uniform sampler2D Texture_Gloss;\n"
330 "#ifdef USECUBEFILTER\n"
331 "uniform samplerCube Texture_Cube;\n"
334 "uniform sampler2D Texture_FogMask;\n"
337 "varying vec2 TexCoord;\n"
338 "varying vec3 CubeVector;\n"
339 "varying vec3 LightVector;\n"
340 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
341 "varying vec3 EyeVector;\n"
348 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
349 " // center and sharp falloff at the edge, this is about the most efficient\n"
350 " // we can get away with as far as providing illumination.\n"
352 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
353 " // provide significant illumination, large = slow = pain.\n"
354 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
358 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
361 "#ifdef USEOFFSETMAPPING\n"
362 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
363 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
364 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
365 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
366 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
367 "#define TexCoord TexCoordOffset\n"
370 " // get the texels - with a blendmap we'd need to blend multiple here\n"
371 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
372 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
373 "#ifdef USESPECULAR\n"
374 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
377 " // calculate shading\n"
378 " vec3 diffusenormal = normalize(LightVector);\n"
379 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
380 "#ifdef USESPECULAR\n"
381 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
384 "#ifdef USECUBEFILTER\n"
385 " // apply light cubemap filter\n"
386 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
389 " // calculate fragment color\n"
390 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
394 void r_shadow_start(void)
397 // allocate vertex processing arrays
399 r_shadow_attenuation2dtexture = NULL;
400 r_shadow_attenuation3dtexture = NULL;
401 r_shadow_texturepool = NULL;
402 r_shadow_filters_texturepool = NULL;
403 R_Shadow_ValidateCvars();
404 R_Shadow_MakeTextures();
405 maxshadowelements = 0;
406 shadowelements = NULL;
414 shadowmarklist = NULL;
416 r_shadow_buffer_numleafpvsbytes = 0;
417 r_shadow_buffer_leafpvs = NULL;
418 r_shadow_buffer_leaflist = NULL;
419 r_shadow_buffer_numsurfacepvsbytes = 0;
420 r_shadow_buffer_surfacepvs = NULL;
421 r_shadow_buffer_surfacelist = NULL;
422 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
423 r_shadow_program_light[i] = 0;
424 if (gl_support_fragment_shader)
426 char *vertstring, *fragstring;
427 int vertstrings_count;
428 int fragstrings_count;
429 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
430 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
431 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
432 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
433 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
435 vertstrings_count = 0;
436 fragstrings_count = 0;
437 if (i & SHADERPERMUTATION_SPECULAR)
439 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
440 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
442 if (i & SHADERPERMUTATION_FOG)
444 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
445 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
447 if (i & SHADERPERMUTATION_CUBEFILTER)
449 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
450 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
452 if (i & SHADERPERMUTATION_OFFSETMAPPING)
454 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
455 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
457 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
458 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
459 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
460 if (!r_shadow_program_light[i])
462 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");
465 qglUseProgramObjectARB(r_shadow_program_light[i]);
466 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
467 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
468 if (i & SHADERPERMUTATION_SPECULAR)
470 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
472 if (i & SHADERPERMUTATION_CUBEFILTER)
474 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
476 if (i & SHADERPERMUTATION_FOG)
478 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
481 qglUseProgramObjectARB(0);
483 Mem_Free(fragstring);
485 Mem_Free(vertstring);
489 void r_shadow_shutdown(void)
492 R_Shadow_UncompileWorldLights();
493 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
495 if (r_shadow_program_light[i])
497 GL_Backend_FreeProgram(r_shadow_program_light[i]);
498 r_shadow_program_light[i] = 0;
502 r_shadow_attenuation2dtexture = NULL;
503 r_shadow_attenuation3dtexture = NULL;
504 R_FreeTexturePool(&r_shadow_texturepool);
505 R_FreeTexturePool(&r_shadow_filters_texturepool);
506 maxshadowelements = 0;
508 Mem_Free(shadowelements);
509 shadowelements = NULL;
512 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
521 Mem_Free(shadowmark);
524 Mem_Free(shadowmarklist);
525 shadowmarklist = NULL;
527 r_shadow_buffer_numleafpvsbytes = 0;
528 if (r_shadow_buffer_leafpvs)
529 Mem_Free(r_shadow_buffer_leafpvs);
530 r_shadow_buffer_leafpvs = NULL;
531 if (r_shadow_buffer_leaflist)
532 Mem_Free(r_shadow_buffer_leaflist);
533 r_shadow_buffer_leaflist = NULL;
534 r_shadow_buffer_numsurfacepvsbytes = 0;
535 if (r_shadow_buffer_surfacepvs)
536 Mem_Free(r_shadow_buffer_surfacepvs);
537 r_shadow_buffer_surfacepvs = NULL;
538 if (r_shadow_buffer_surfacelist)
539 Mem_Free(r_shadow_buffer_surfacelist);
540 r_shadow_buffer_surfacelist = NULL;
543 void r_shadow_newmap(void)
547 void R_Shadow_Help_f(void)
550 "Documentation on r_shadow system:\n"
552 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
553 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
554 "r_shadow_debuglight : render only this light number (-1 = all)\n"
555 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
556 "r_shadow_gloss2intensity : brightness of forced gloss\n"
557 "r_shadow_glossintensity : brightness of textured gloss\n"
558 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
559 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
560 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
561 "r_shadow_portallight : use portal visibility for static light precomputation\n"
562 "r_shadow_projectdistance : shadow volume projection distance\n"
563 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
564 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
565 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
566 "r_shadow_realtime_world : use high quality world lighting mode\n"
567 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
568 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
569 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
570 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
571 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
572 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
573 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
574 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
575 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
576 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
577 "r_shadow_scissor : use scissor optimization\n"
578 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
579 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
580 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
581 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
582 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
583 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
585 "r_shadow_help : this help\n"
589 void R_Shadow_Init(void)
591 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
592 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
593 Cvar_RegisterVariable(&r_shadow_debuglight);
594 Cvar_RegisterVariable(&r_shadow_gloss);
595 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
596 Cvar_RegisterVariable(&r_shadow_glossintensity);
597 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
598 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
599 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
600 Cvar_RegisterVariable(&r_shadow_portallight);
601 Cvar_RegisterVariable(&r_shadow_projectdistance);
602 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
603 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
604 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
605 Cvar_RegisterVariable(&r_shadow_realtime_world);
606 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
607 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
608 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
609 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
610 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
611 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
612 Cvar_RegisterVariable(&r_shadow_scissor);
613 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
614 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
615 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
616 Cvar_RegisterVariable(&r_shadow_texture3d);
617 Cvar_RegisterVariable(&r_shadow_visiblelighting);
618 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
619 Cvar_RegisterVariable(&r_shadow_glsl);
620 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
621 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
622 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
623 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
624 if (gamemode == GAME_TENEBRAE)
626 Cvar_SetValue("r_shadow_gloss", 2);
627 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
629 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
630 R_Shadow_EditLights_Init();
631 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
632 r_shadow_worldlightchain = NULL;
633 maxshadowelements = 0;
634 shadowelements = NULL;
642 shadowmarklist = NULL;
644 r_shadow_buffer_numleafpvsbytes = 0;
645 r_shadow_buffer_leafpvs = NULL;
646 r_shadow_buffer_leaflist = NULL;
647 r_shadow_buffer_numsurfacepvsbytes = 0;
648 r_shadow_buffer_surfacepvs = NULL;
649 r_shadow_buffer_surfacelist = NULL;
650 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
653 static matrix4x4_t matrix_attenuationxyz =
656 {0.5, 0.0, 0.0, 0.5},
657 {0.0, 0.5, 0.0, 0.5},
658 {0.0, 0.0, 0.5, 0.5},
663 static matrix4x4_t matrix_attenuationz =
666 {0.0, 0.0, 0.5, 0.5},
667 {0.0, 0.0, 0.0, 0.5},
668 {0.0, 0.0, 0.0, 0.5},
673 int *R_Shadow_ResizeShadowElements(int numtris)
675 // make sure shadowelements is big enough for this volume
676 if (maxshadowelements < numtris * 24)
678 maxshadowelements = numtris * 24;
680 Mem_Free(shadowelements);
681 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
683 return shadowelements;
686 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
688 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
689 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
690 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
692 if (r_shadow_buffer_leafpvs)
693 Mem_Free(r_shadow_buffer_leafpvs);
694 if (r_shadow_buffer_leaflist)
695 Mem_Free(r_shadow_buffer_leaflist);
696 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
697 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
698 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
700 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
702 if (r_shadow_buffer_surfacepvs)
703 Mem_Free(r_shadow_buffer_surfacepvs);
704 if (r_shadow_buffer_surfacelist)
705 Mem_Free(r_shadow_buffer_surfacelist);
706 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
707 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
708 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
712 void R_Shadow_PrepareShadowMark(int numtris)
714 // make sure shadowmark is big enough for this volume
715 if (maxshadowmark < numtris)
717 maxshadowmark = numtris;
719 Mem_Free(shadowmark);
721 Mem_Free(shadowmarklist);
722 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
723 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
727 // if shadowmarkcount wrapped we clear the array and adjust accordingly
728 if (shadowmarkcount == 0)
731 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
736 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)
739 int outtriangles = 0, outvertices = 0;
743 if (maxvertexupdate < innumvertices)
745 maxvertexupdate = innumvertices;
747 Mem_Free(vertexupdate);
749 Mem_Free(vertexremap);
750 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
751 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
755 if (vertexupdatenum == 0)
758 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
759 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
762 for (i = 0;i < numshadowmarktris;i++)
763 shadowmark[shadowmarktris[i]] = shadowmarkcount;
765 for (i = 0;i < numshadowmarktris;i++)
767 element = inelement3i + shadowmarktris[i] * 3;
768 // make sure the vertices are created
769 for (j = 0;j < 3;j++)
771 if (vertexupdate[element[j]] != vertexupdatenum)
773 float ratio, direction[3];
774 vertexupdate[element[j]] = vertexupdatenum;
775 vertexremap[element[j]] = outvertices;
776 vertex = invertex3f + element[j] * 3;
777 // project one copy of the vertex to the sphere radius of the light
778 // (FIXME: would projecting it to the light box be better?)
779 VectorSubtract(vertex, projectorigin, direction);
780 ratio = projectdistance / VectorLength(direction);
781 VectorCopy(vertex, outvertex3f);
782 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
789 for (i = 0;i < numshadowmarktris;i++)
791 int remappedelement[3];
793 const int *neighbortriangle;
795 markindex = shadowmarktris[i] * 3;
796 element = inelement3i + markindex;
797 neighbortriangle = inneighbor3i + markindex;
798 // output the front and back triangles
799 outelement3i[0] = vertexremap[element[0]];
800 outelement3i[1] = vertexremap[element[1]];
801 outelement3i[2] = vertexremap[element[2]];
802 outelement3i[3] = vertexremap[element[2]] + 1;
803 outelement3i[4] = vertexremap[element[1]] + 1;
804 outelement3i[5] = vertexremap[element[0]] + 1;
808 // output the sides (facing outward from this triangle)
809 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
811 remappedelement[0] = vertexremap[element[0]];
812 remappedelement[1] = vertexremap[element[1]];
813 outelement3i[0] = remappedelement[1];
814 outelement3i[1] = remappedelement[0];
815 outelement3i[2] = remappedelement[0] + 1;
816 outelement3i[3] = remappedelement[1];
817 outelement3i[4] = remappedelement[0] + 1;
818 outelement3i[5] = remappedelement[1] + 1;
823 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
825 remappedelement[1] = vertexremap[element[1]];
826 remappedelement[2] = vertexremap[element[2]];
827 outelement3i[0] = remappedelement[2];
828 outelement3i[1] = remappedelement[1];
829 outelement3i[2] = remappedelement[1] + 1;
830 outelement3i[3] = remappedelement[2];
831 outelement3i[4] = remappedelement[1] + 1;
832 outelement3i[5] = remappedelement[2] + 1;
837 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
839 remappedelement[0] = vertexremap[element[0]];
840 remappedelement[2] = vertexremap[element[2]];
841 outelement3i[0] = remappedelement[0];
842 outelement3i[1] = remappedelement[2];
843 outelement3i[2] = remappedelement[2] + 1;
844 outelement3i[3] = remappedelement[0];
845 outelement3i[4] = remappedelement[2] + 1;
846 outelement3i[5] = remappedelement[0] + 1;
853 *outnumvertices = outvertices;
857 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)
860 if (projectdistance < 0.1)
862 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
865 if (!numverts || !nummarktris)
867 // make sure shadowelements is big enough for this volume
868 if (maxshadowelements < nummarktris * 24)
869 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
870 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
871 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
874 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)
879 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
881 tend = firsttriangle + numtris;
882 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
883 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
884 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
886 // surface box entirely inside light box, no box cull
887 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
888 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
889 shadowmarklist[numshadowmark++] = t;
893 // surface box not entirely inside light box, cull each triangle
894 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
896 v[0] = invertex3f + e[0] * 3;
897 v[1] = invertex3f + e[1] * 3;
898 v[2] = invertex3f + e[2] * 3;
899 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
900 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
901 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
902 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
903 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
904 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
905 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
906 shadowmarklist[numshadowmark++] = t;
911 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
914 if (r_shadow_compilingrtlight)
916 // if we're compiling an rtlight, capture the mesh
917 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
920 memset(&m, 0, sizeof(m));
921 m.pointer_vertex = vertex3f;
923 GL_LockArrays(0, numvertices);
924 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
926 // increment stencil if backface is behind depthbuffer
927 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
928 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
929 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
931 c_rt_shadowtris += numtriangles;
932 // decrement stencil if frontface is behind depthbuffer
933 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
934 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
936 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
938 c_rt_shadowtris += numtriangles;
942 static void R_Shadow_MakeTextures(void)
945 float v[3], intensity;
947 R_FreeTexturePool(&r_shadow_texturepool);
948 r_shadow_texturepool = R_AllocTexturePool();
949 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
950 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
951 #define ATTEN2DSIZE 64
952 #define ATTEN3DSIZE 32
953 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
954 for (y = 0;y < ATTEN2DSIZE;y++)
956 for (x = 0;x < ATTEN2DSIZE;x++)
958 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
959 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
961 intensity = 1.0f - sqrt(DotProduct(v, v));
963 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
964 d = bound(0, intensity, 255);
965 data[(y*ATTEN2DSIZE+x)*4+0] = d;
966 data[(y*ATTEN2DSIZE+x)*4+1] = d;
967 data[(y*ATTEN2DSIZE+x)*4+2] = d;
968 data[(y*ATTEN2DSIZE+x)*4+3] = d;
971 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
972 if (r_shadow_texture3d.integer)
974 for (z = 0;z < ATTEN3DSIZE;z++)
976 for (y = 0;y < ATTEN3DSIZE;y++)
978 for (x = 0;x < ATTEN3DSIZE;x++)
980 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
981 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
982 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
983 intensity = 1.0f - sqrt(DotProduct(v, v));
985 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
986 d = bound(0, intensity, 255);
987 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
988 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
989 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
990 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
994 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
999 void R_Shadow_ValidateCvars(void)
1001 if (r_shadow_texture3d.integer && !gl_texture3d)
1002 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1003 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1004 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1007 // light currently being rendered
1008 static rtlight_t *r_shadow_rtlight;
1009 // light filter cubemap being used by the light
1010 static rtexture_t *r_shadow_lightcubemap;
1012 // this is the location of the eye in entity space
1013 static vec3_t r_shadow_entityeyeorigin;
1014 // this is the location of the light in entity space
1015 static vec3_t r_shadow_entitylightorigin;
1016 // this transforms entity coordinates to light filter cubemap coordinates
1017 // (also often used for other purposes)
1018 static matrix4x4_t r_shadow_entitytolight;
1019 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1020 // of attenuation texturing in full 3D (Z result often ignored)
1021 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1022 // this transforms only the Z to S, and T is always 0.5
1023 static matrix4x4_t r_shadow_entitytoattenuationz;
1024 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1025 static vec3_t r_shadow_entitylightcolor;
1027 static int r_shadow_lightpermutation;
1028 static int r_shadow_lightprog;
1030 void R_Shadow_Stage_Begin(void)
1034 R_Shadow_ValidateCvars();
1036 if (!r_shadow_attenuation2dtexture
1037 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1038 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1039 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1040 R_Shadow_MakeTextures();
1042 memset(&m, 0, sizeof(m));
1043 GL_BlendFunc(GL_ONE, GL_ZERO);
1044 GL_DepthMask(false);
1047 GL_Color(0, 0, 0, 1);
1048 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1049 qglEnable(GL_CULL_FACE);
1050 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1051 r_shadowstage = R_SHADOWSTAGE_NONE;
1054 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1056 r_shadow_rtlight = rtlight;
1059 void R_Shadow_Stage_Reset(void)
1062 if (gl_support_stenciltwoside)
1063 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1064 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1066 qglUseProgramObjectARB(0);
1067 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1068 qglBegin(GL_TRIANGLES);
1072 memset(&m, 0, sizeof(m));
1076 void R_Shadow_Stage_StencilShadowVolumes(void)
1078 R_Shadow_Stage_Reset();
1079 GL_Color(1, 1, 1, 1);
1080 GL_ColorMask(0, 0, 0, 0);
1081 GL_BlendFunc(GL_ONE, GL_ZERO);
1082 GL_DepthMask(false);
1084 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1085 //if (r_shadow_shadow_polygonoffset.value != 0)
1087 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1088 // qglEnable(GL_POLYGON_OFFSET_FILL);
1091 // qglDisable(GL_POLYGON_OFFSET_FILL);
1092 qglDepthFunc(GL_GEQUAL);
1093 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1094 qglEnable(GL_STENCIL_TEST);
1095 qglStencilFunc(GL_ALWAYS, 128, ~0);
1096 if (gl_ext_stenciltwoside.integer)
1098 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1099 qglDisable(GL_CULL_FACE);
1100 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1101 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1103 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
1104 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1106 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1110 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1111 qglEnable(GL_CULL_FACE);
1113 // this is changed by every shadow render so its value here is unimportant
1114 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1116 GL_Clear(GL_STENCIL_BUFFER_BIT);
1120 void R_Shadow_Stage_Lighting(int stenciltest)
1123 R_Shadow_Stage_Reset();
1124 GL_BlendFunc(GL_ONE, GL_ONE);
1125 GL_DepthMask(false);
1127 qglPolygonOffset(0, 0);
1128 //qglDisable(GL_POLYGON_OFFSET_FILL);
1129 GL_Color(1, 1, 1, 1);
1130 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1131 qglDepthFunc(GL_EQUAL);
1132 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1133 qglEnable(GL_CULL_FACE);
1134 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1135 qglEnable(GL_STENCIL_TEST);
1137 qglDisable(GL_STENCIL_TEST);
1139 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1140 // only draw light where this geometry was already rendered AND the
1141 // stencil is 128 (values other than this mean shadow)
1142 qglStencilFunc(GL_EQUAL, 128, ~0);
1143 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1145 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1146 memset(&m, 0, sizeof(m));
1147 m.pointer_vertex = varray_vertex3f;
1148 m.pointer_texcoord[0] = varray_texcoord2f[0];
1149 m.pointer_texcoord3f[1] = varray_svector3f;
1150 m.pointer_texcoord3f[2] = varray_tvector3f;
1151 m.pointer_texcoord3f[3] = varray_normal3f;
1152 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1153 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1154 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1155 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1156 // TODO: support fog (after renderer is converted to texture fog)
1157 m.tex[4] = R_GetTexture(r_texture_white); // fog
1158 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1160 GL_BlendFunc(GL_ONE, GL_ONE);
1161 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1163 r_shadow_lightpermutation = 0;
1164 // only add a feature to the permutation if that permutation exists
1165 // (otherwise it might end up not using a shader at all, which looks
1166 // worse than using less features)
1167 if (r_shadow_rtlight->specularscale && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1168 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1169 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1170 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1171 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1172 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1173 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1174 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1175 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1176 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1177 // TODO: support fog (after renderer is converted to texture fog)
1178 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1180 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1182 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1183 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1184 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1186 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1187 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1189 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1190 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1191 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1193 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1195 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1197 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1198 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1201 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1202 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1204 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1207 void R_Shadow_Stage_VisibleShadowVolumes(void)
1209 R_Shadow_Stage_Reset();
1210 GL_BlendFunc(GL_ONE, GL_ONE);
1211 GL_DepthMask(false);
1212 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1213 qglPolygonOffset(0, 0);
1214 GL_Color(0.0, 0.0125, 0.1, 1);
1215 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1216 qglDepthFunc(GL_GEQUAL);
1217 qglCullFace(GL_FRONT); // this culls back
1218 qglDisable(GL_CULL_FACE);
1219 qglDisable(GL_STENCIL_TEST);
1220 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1223 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1225 R_Shadow_Stage_Reset();
1226 GL_BlendFunc(GL_ONE, GL_ONE);
1227 GL_DepthMask(false);
1228 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1229 qglPolygonOffset(0, 0);
1230 GL_Color(0.1, 0.0125, 0, 1);
1231 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1232 qglDepthFunc(GL_EQUAL);
1233 qglCullFace(GL_FRONT); // this culls back
1234 qglEnable(GL_CULL_FACE);
1236 qglEnable(GL_STENCIL_TEST);
1238 qglDisable(GL_STENCIL_TEST);
1239 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1242 void R_Shadow_Stage_End(void)
1244 R_Shadow_Stage_Reset();
1245 R_Shadow_Stage_ActiveLight(NULL);
1246 GL_BlendFunc(GL_ONE, GL_ZERO);
1249 qglPolygonOffset(0, 0);
1250 //qglDisable(GL_POLYGON_OFFSET_FILL);
1251 GL_Color(1, 1, 1, 1);
1252 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1253 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1254 qglDepthFunc(GL_LEQUAL);
1255 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1256 qglDisable(GL_STENCIL_TEST);
1257 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1258 if (gl_support_stenciltwoside)
1259 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1261 qglStencilFunc(GL_ALWAYS, 128, ~0);
1262 r_shadowstage = R_SHADOWSTAGE_NONE;
1265 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1267 int i, ix1, iy1, ix2, iy2;
1268 float x1, y1, x2, y2;
1271 mplane_t planes[11];
1272 float vertex3f[256*3];
1274 // if view is inside the light box, just say yes it's visible
1275 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1277 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1281 // create a temporary brush describing the area the light can affect in worldspace
1282 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1283 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1284 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1285 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1286 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1287 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1288 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1289 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1290 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1291 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1292 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1294 // turn the brush into a mesh
1295 memset(&mesh, 0, sizeof(rmesh_t));
1296 mesh.maxvertices = 256;
1297 mesh.vertex3f = vertex3f;
1298 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1299 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1301 // if that mesh is empty, the light is not visible at all
1302 if (!mesh.numvertices)
1305 if (!r_shadow_scissor.integer)
1308 // if that mesh is not empty, check what area of the screen it covers
1309 x1 = y1 = x2 = y2 = 0;
1311 for (i = 0;i < mesh.numvertices;i++)
1313 VectorCopy(mesh.vertex3f + i * 3, v);
1314 GL_TransformToScreen(v, v2);
1315 //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]);
1318 if (x1 > v2[0]) x1 = v2[0];
1319 if (x2 < v2[0]) x2 = v2[0];
1320 if (y1 > v2[1]) y1 = v2[1];
1321 if (y2 < v2[1]) y2 = v2[1];
1330 // now convert the scissor rectangle to integer screen coordinates
1335 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1337 // clamp it to the screen
1338 if (ix1 < r_view_x) ix1 = r_view_x;
1339 if (iy1 < r_view_y) iy1 = r_view_y;
1340 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1341 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1343 // if it is inside out, it's not visible
1344 if (ix2 <= ix1 || iy2 <= iy1)
1347 // the light area is visible, set up the scissor rectangle
1348 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1349 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1350 //qglEnable(GL_SCISSOR_TEST);
1355 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1357 float *color4f = varray_color4f;
1358 float dist, dot, intensity, v[3], n[3];
1359 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1361 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1362 if ((dist = DotProduct(v, v)) < 1)
1364 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1365 if ((dot = DotProduct(n, v)) > 0)
1368 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1369 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1370 VectorScale(lightcolor, intensity, color4f);
1375 VectorClear(color4f);
1381 VectorClear(color4f);
1387 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1389 float *color4f = varray_color4f;
1390 float dist, dot, intensity, v[3], n[3];
1391 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1393 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1394 if ((dist = fabs(v[2])) < 1)
1396 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1397 if ((dot = DotProduct(n, v)) > 0)
1399 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1400 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1401 VectorScale(lightcolor, intensity, color4f);
1406 VectorClear(color4f);
1412 VectorClear(color4f);
1418 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1420 float *color4f = varray_color4f;
1421 float dot, intensity, v[3], n[3];
1422 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1424 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1425 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1426 if ((dot = DotProduct(n, v)) > 0)
1428 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1429 VectorScale(lightcolor, intensity, color4f);
1434 VectorClear(color4f);
1440 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1442 float *color4f = varray_color4f;
1443 float dist, intensity, v[3];
1444 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1446 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1447 if ((dist = DotProduct(v, v)) < 1)
1450 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1451 VectorScale(lightcolor, intensity, color4f);
1456 VectorClear(color4f);
1462 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1464 float *color4f = varray_color4f;
1465 float dist, intensity, v[3];
1466 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1468 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1469 if ((dist = fabs(v[2])) < 1)
1471 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1472 VectorScale(lightcolor, intensity, color4f);
1477 VectorClear(color4f);
1483 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1484 #define USETEXMATRIX
1486 #ifndef USETEXMATRIX
1487 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1488 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1489 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1493 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1494 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1495 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1502 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1506 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1507 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1515 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)
1519 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1521 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1522 // the cubemap normalizes this for us
1523 out3f[0] = DotProduct(svector3f, lightdir);
1524 out3f[1] = DotProduct(tvector3f, lightdir);
1525 out3f[2] = DotProduct(normal3f, lightdir);
1529 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)
1532 float lightdir[3], eyedir[3], halfdir[3];
1533 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1535 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1536 VectorNormalizeFast(lightdir);
1537 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1538 VectorNormalizeFast(eyedir);
1539 VectorAdd(lightdir, eyedir, halfdir);
1540 // the cubemap normalizes this for us
1541 out3f[0] = DotProduct(svector3f, halfdir);
1542 out3f[1] = DotProduct(tvector3f, halfdir);
1543 out3f[2] = DotProduct(normal3f, halfdir);
1547 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture)
1550 float color[3], color2[3], colorscale, specularscale;
1552 // FIXME: support EF_NODEPTHTEST
1554 basetexture = r_texture_white;
1556 bumptexture = r_texture_blanknormalmap;
1558 lightcolorpants = vec3_origin;
1560 lightcolorshirt = vec3_origin;
1561 if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1562 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
1563 else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1565 glosstexture = r_texture_white;
1566 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
1570 glosstexture = r_texture_black;
1573 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1575 if (r_shadowstage == R_SHADOWSTAGE_VISIBLELIGHTING)
1578 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1579 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1580 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1582 // TODO: add direct pants/shirt rendering
1583 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1584 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1585 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1586 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1587 if (r_shadow_rtlight->ambientscale)
1589 colorscale = r_shadow_rtlight->ambientscale;
1590 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1593 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1596 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1599 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1604 VectorScale(lightcolorbase, colorscale, color2);
1605 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1608 if (r_shadow_rtlight->diffusescale)
1610 colorscale = r_shadow_rtlight->diffusescale;
1611 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1613 // 3/2 3D combine path (Geforce3, Radeon 8500)
1616 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1618 // 1/2/2 3D combine path (original Radeon)
1621 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1623 // 2/2 3D combine path (original Radeon)
1626 else if (r_textureunits.integer >= 4)
1628 // 4/2 2D combine path (Geforce3, Radeon 8500)
1633 // 2/2/2 2D combine path (any dot3 card)
1636 VectorScale(lightcolorbase, colorscale, color2);
1637 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1640 if (specularscale && glosstexture != r_texture_black)
1642 //if (gl_support_blendsquare)
1644 colorscale = specularscale;
1645 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1647 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1651 VectorScale(lightcolorbase, colorscale, color2);
1652 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1659 // TODO: add direct pants/shirt rendering
1660 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1661 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1662 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1663 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1664 if (r_shadow_rtlight->ambientscale)
1666 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
1667 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1670 if (r_shadow_rtlight->diffusescale)
1672 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
1673 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1679 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1680 memset(&m, 0, sizeof(m));
1681 m.pointer_vertex = vertex3f;
1683 GL_LockArrays(firstvertex, numvertices);
1684 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1685 GL_LockArrays(0, 0);
1689 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1691 // GLSL shader path (GFFX5200, Radeon 9500)
1692 R_Mesh_VertexPointer(vertex3f);
1693 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1694 R_Mesh_TexCoordPointer(1, 3, svector3f);
1695 R_Mesh_TexCoordPointer(2, 3, tvector3f);
1696 R_Mesh_TexCoordPointer(3, 3, normal3f);
1697 R_Mesh_TexBind(0, R_GetTexture(bumptexture));
1698 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1699 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1700 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1702 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1704 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1705 GL_LockArrays(firstvertex, numvertices);
1706 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1708 c_rt_lighttris += numtriangles;
1709 // TODO: add direct pants/shirt rendering
1710 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1712 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1713 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1714 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1716 c_rt_lighttris += numtriangles;
1718 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1720 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1721 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1722 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1724 c_rt_lighttris += numtriangles;
1726 GL_LockArrays(0, 0);
1728 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
1730 // TODO: add direct pants/shirt rendering
1731 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1732 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1733 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1734 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1735 if (r_shadow_rtlight->ambientscale)
1738 colorscale = r_shadow_rtlight->ambientscale;
1739 // colorscale accounts for how much we multiply the brightness
1742 // mult is how many times the final pass of the lighting will be
1743 // performed to get more brightness than otherwise possible.
1745 // Limit mult to 64 for sanity sake.
1746 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1748 // 3 3D combine path (Geforce3, Radeon 8500)
1749 memset(&m, 0, sizeof(m));
1750 m.pointer_vertex = vertex3f;
1751 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1753 m.pointer_texcoord3f[0] = vertex3f;
1754 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1756 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1757 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1759 m.tex[1] = R_GetTexture(basetexture);
1760 m.pointer_texcoord[1] = texcoord2f;
1761 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1763 m.pointer_texcoord3f[2] = vertex3f;
1764 m.texmatrix[2] = r_shadow_entitytolight;
1766 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1767 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1769 GL_BlendFunc(GL_ONE, GL_ONE);
1771 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1773 // 2 3D combine path (Geforce3, original Radeon)
1774 memset(&m, 0, sizeof(m));
1775 m.pointer_vertex = vertex3f;
1776 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1778 m.pointer_texcoord3f[0] = vertex3f;
1779 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1781 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1782 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1784 m.tex[1] = R_GetTexture(basetexture);
1785 m.pointer_texcoord[1] = texcoord2f;
1786 GL_BlendFunc(GL_ONE, GL_ONE);
1788 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1790 // 4 2D combine path (Geforce3, Radeon 8500)
1791 memset(&m, 0, sizeof(m));
1792 m.pointer_vertex = vertex3f;
1793 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1795 m.pointer_texcoord3f[0] = vertex3f;
1796 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1798 m.pointer_texcoord[0] = varray_texcoord2f[0];
1799 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1801 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1803 m.pointer_texcoord3f[1] = vertex3f;
1804 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1806 m.pointer_texcoord[1] = varray_texcoord2f[1];
1807 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1809 m.tex[2] = R_GetTexture(basetexture);
1810 m.pointer_texcoord[2] = texcoord2f;
1811 if (r_shadow_lightcubemap != r_texture_whitecube)
1813 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1815 m.pointer_texcoord3f[3] = vertex3f;
1816 m.texmatrix[3] = r_shadow_entitytolight;
1818 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1819 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1822 GL_BlendFunc(GL_ONE, GL_ONE);
1824 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1826 // 3 2D combine path (Geforce3, original Radeon)
1827 memset(&m, 0, sizeof(m));
1828 m.pointer_vertex = vertex3f;
1829 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1831 m.pointer_texcoord3f[0] = vertex3f;
1832 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1834 m.pointer_texcoord[0] = varray_texcoord2f[0];
1835 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1837 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1839 m.pointer_texcoord3f[1] = vertex3f;
1840 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1842 m.pointer_texcoord[1] = varray_texcoord2f[1];
1843 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1845 m.tex[2] = R_GetTexture(basetexture);
1846 m.pointer_texcoord[2] = texcoord2f;
1847 GL_BlendFunc(GL_ONE, GL_ONE);
1851 // 2/2/2 2D combine path (any dot3 card)
1852 memset(&m, 0, sizeof(m));
1853 m.pointer_vertex = vertex3f;
1854 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1856 m.pointer_texcoord3f[0] = vertex3f;
1857 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1859 m.pointer_texcoord[0] = varray_texcoord2f[0];
1860 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1862 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1864 m.pointer_texcoord3f[1] = vertex3f;
1865 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1867 m.pointer_texcoord[1] = varray_texcoord2f[1];
1868 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1871 GL_ColorMask(0,0,0,1);
1872 GL_BlendFunc(GL_ONE, GL_ZERO);
1873 GL_LockArrays(firstvertex, numvertices);
1874 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1875 GL_LockArrays(0, 0);
1877 c_rt_lighttris += numtriangles;
1879 memset(&m, 0, sizeof(m));
1880 m.pointer_vertex = vertex3f;
1881 m.tex[0] = R_GetTexture(basetexture);
1882 m.pointer_texcoord[0] = texcoord2f;
1883 if (r_shadow_lightcubemap != r_texture_whitecube)
1885 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1887 m.pointer_texcoord3f[1] = vertex3f;
1888 m.texmatrix[1] = r_shadow_entitytolight;
1890 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1891 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1894 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1896 // this final code is shared
1898 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1899 VectorScale(lightcolorbase, colorscale, color2);
1900 GL_LockArrays(firstvertex, numvertices);
1901 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1903 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1904 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1906 c_rt_lighttris += numtriangles;
1908 GL_LockArrays(0, 0);
1910 if (r_shadow_rtlight->diffusescale)
1913 colorscale = r_shadow_rtlight->diffusescale;
1914 // colorscale accounts for how much we multiply the brightness
1917 // mult is how many times the final pass of the lighting will be
1918 // performed to get more brightness than otherwise possible.
1920 // Limit mult to 64 for sanity sake.
1921 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1923 // 3/2 3D combine path (Geforce3, Radeon 8500)
1924 memset(&m, 0, sizeof(m));
1925 m.pointer_vertex = vertex3f;
1926 m.tex[0] = R_GetTexture(bumptexture);
1927 m.texcombinergb[0] = GL_REPLACE;
1928 m.pointer_texcoord[0] = texcoord2f;
1929 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1930 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1931 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1932 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
1933 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1935 m.pointer_texcoord3f[2] = vertex3f;
1936 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1938 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1939 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1942 GL_ColorMask(0,0,0,1);
1943 GL_BlendFunc(GL_ONE, GL_ZERO);
1944 GL_LockArrays(firstvertex, numvertices);
1945 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1946 GL_LockArrays(0, 0);
1948 c_rt_lighttris += numtriangles;
1950 memset(&m, 0, sizeof(m));
1951 m.pointer_vertex = vertex3f;
1952 m.tex[0] = R_GetTexture(basetexture);
1953 m.pointer_texcoord[0] = texcoord2f;
1954 if (r_shadow_lightcubemap != r_texture_whitecube)
1956 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1958 m.pointer_texcoord3f[1] = vertex3f;
1959 m.texmatrix[1] = r_shadow_entitytolight;
1961 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1962 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1965 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1967 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1969 // 1/2/2 3D combine path (original Radeon)
1970 memset(&m, 0, sizeof(m));
1971 m.pointer_vertex = vertex3f;
1972 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1974 m.pointer_texcoord3f[0] = vertex3f;
1975 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1977 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1978 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1981 GL_ColorMask(0,0,0,1);
1982 GL_BlendFunc(GL_ONE, GL_ZERO);
1983 GL_LockArrays(firstvertex, numvertices);
1984 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1985 GL_LockArrays(0, 0);
1987 c_rt_lighttris += numtriangles;
1989 memset(&m, 0, sizeof(m));
1990 m.pointer_vertex = vertex3f;
1991 m.tex[0] = R_GetTexture(bumptexture);
1992 m.texcombinergb[0] = GL_REPLACE;
1993 m.pointer_texcoord[0] = texcoord2f;
1994 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1995 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1996 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1997 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
1999 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2000 GL_LockArrays(firstvertex, numvertices);
2001 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2002 GL_LockArrays(0, 0);
2004 c_rt_lighttris += numtriangles;
2006 memset(&m, 0, sizeof(m));
2007 m.pointer_vertex = vertex3f;
2008 m.tex[0] = R_GetTexture(basetexture);
2009 m.pointer_texcoord[0] = texcoord2f;
2010 if (r_shadow_lightcubemap != r_texture_whitecube)
2012 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2014 m.pointer_texcoord3f[1] = vertex3f;
2015 m.texmatrix[1] = r_shadow_entitytolight;
2017 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2018 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2021 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2023 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2025 // 2/2 3D combine path (original Radeon)
2026 memset(&m, 0, sizeof(m));
2027 m.pointer_vertex = vertex3f;
2028 m.tex[0] = R_GetTexture(bumptexture);
2029 m.texcombinergb[0] = GL_REPLACE;
2030 m.pointer_texcoord[0] = texcoord2f;
2031 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2032 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2033 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2034 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2036 GL_ColorMask(0,0,0,1);
2037 GL_BlendFunc(GL_ONE, GL_ZERO);
2038 GL_LockArrays(firstvertex, numvertices);
2039 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2040 GL_LockArrays(0, 0);
2042 c_rt_lighttris += numtriangles;
2044 memset(&m, 0, sizeof(m));
2045 m.pointer_vertex = vertex3f;
2046 m.tex[0] = R_GetTexture(basetexture);
2047 m.pointer_texcoord[0] = texcoord2f;
2048 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2050 m.pointer_texcoord3f[1] = vertex3f;
2051 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2053 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2054 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2056 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2058 else if (r_textureunits.integer >= 4)
2060 // 4/2 2D combine path (Geforce3, Radeon 8500)
2061 memset(&m, 0, sizeof(m));
2062 m.pointer_vertex = vertex3f;
2063 m.tex[0] = R_GetTexture(bumptexture);
2064 m.texcombinergb[0] = GL_REPLACE;
2065 m.pointer_texcoord[0] = texcoord2f;
2066 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2067 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2068 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2069 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2070 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2072 m.pointer_texcoord3f[2] = vertex3f;
2073 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2075 m.pointer_texcoord[2] = varray_texcoord2f[2];
2076 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2078 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2080 m.pointer_texcoord3f[3] = vertex3f;
2081 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2083 m.pointer_texcoord[3] = varray_texcoord2f[3];
2084 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2087 GL_ColorMask(0,0,0,1);
2088 GL_BlendFunc(GL_ONE, GL_ZERO);
2089 GL_LockArrays(firstvertex, numvertices);
2090 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2091 GL_LockArrays(0, 0);
2093 c_rt_lighttris += numtriangles;
2095 memset(&m, 0, sizeof(m));
2096 m.pointer_vertex = vertex3f;
2097 m.tex[0] = R_GetTexture(basetexture);
2098 m.pointer_texcoord[0] = texcoord2f;
2099 if (r_shadow_lightcubemap != r_texture_whitecube)
2101 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2103 m.pointer_texcoord3f[1] = vertex3f;
2104 m.texmatrix[1] = r_shadow_entitytolight;
2106 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2107 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2110 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2114 // 2/2/2 2D combine path (any dot3 card)
2115 memset(&m, 0, sizeof(m));
2116 m.pointer_vertex = vertex3f;
2117 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2119 m.pointer_texcoord3f[0] = vertex3f;
2120 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2122 m.pointer_texcoord[0] = varray_texcoord2f[0];
2123 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2125 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2127 m.pointer_texcoord3f[1] = vertex3f;
2128 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2130 m.pointer_texcoord[1] = varray_texcoord2f[1];
2131 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2134 GL_ColorMask(0,0,0,1);
2135 GL_BlendFunc(GL_ONE, GL_ZERO);
2136 GL_LockArrays(firstvertex, numvertices);
2137 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2138 GL_LockArrays(0, 0);
2140 c_rt_lighttris += numtriangles;
2142 memset(&m, 0, sizeof(m));
2143 m.pointer_vertex = vertex3f;
2144 m.tex[0] = R_GetTexture(bumptexture);
2145 m.texcombinergb[0] = GL_REPLACE;
2146 m.pointer_texcoord[0] = texcoord2f;
2147 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2148 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2149 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2150 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2152 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2153 GL_LockArrays(firstvertex, numvertices);
2154 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2155 GL_LockArrays(0, 0);
2157 c_rt_lighttris += numtriangles;
2159 memset(&m, 0, sizeof(m));
2160 m.pointer_vertex = vertex3f;
2161 m.tex[0] = R_GetTexture(basetexture);
2162 m.pointer_texcoord[0] = texcoord2f;
2163 if (r_shadow_lightcubemap != r_texture_whitecube)
2165 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2167 m.pointer_texcoord3f[1] = vertex3f;
2168 m.texmatrix[1] = r_shadow_entitytolight;
2170 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2171 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2174 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2176 // this final code is shared
2178 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2179 VectorScale(lightcolorbase, colorscale, color2);
2180 GL_LockArrays(firstvertex, numvertices);
2181 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2183 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2184 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2186 c_rt_lighttris += numtriangles;
2188 GL_LockArrays(0, 0);
2190 if (specularscale && glosstexture != r_texture_black)
2192 // FIXME: detect blendsquare!
2193 //if (gl_support_blendsquare)
2195 colorscale = specularscale;
2197 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2199 // 2/0/0/1/2 3D combine blendsquare path
2200 memset(&m, 0, sizeof(m));
2201 m.pointer_vertex = vertex3f;
2202 m.tex[0] = R_GetTexture(bumptexture);
2203 m.pointer_texcoord[0] = texcoord2f;
2204 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2205 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2206 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2207 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2209 GL_ColorMask(0,0,0,1);
2210 // this squares the result
2211 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2212 GL_LockArrays(firstvertex, numvertices);
2213 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2214 GL_LockArrays(0, 0);
2216 c_rt_lighttris += numtriangles;
2218 memset(&m, 0, sizeof(m));
2219 m.pointer_vertex = vertex3f;
2221 GL_LockArrays(firstvertex, numvertices);
2222 // square alpha in framebuffer a few times to make it shiny
2223 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2224 // these comments are a test run through this math for intensity 0.5
2225 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2226 // 0.25 * 0.25 = 0.0625 (this is another pass)
2227 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2228 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2230 c_rt_lighttris += numtriangles;
2231 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2233 c_rt_lighttris += numtriangles;
2234 GL_LockArrays(0, 0);
2236 memset(&m, 0, sizeof(m));
2237 m.pointer_vertex = vertex3f;
2238 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2240 m.pointer_texcoord3f[0] = vertex3f;
2241 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2243 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2244 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2247 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2248 GL_LockArrays(firstvertex, numvertices);
2249 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2250 GL_LockArrays(0, 0);
2252 c_rt_lighttris += numtriangles;
2254 memset(&m, 0, sizeof(m));
2255 m.pointer_vertex = vertex3f;
2256 m.tex[0] = R_GetTexture(glosstexture);
2257 m.pointer_texcoord[0] = texcoord2f;
2258 if (r_shadow_lightcubemap != r_texture_whitecube)
2260 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2262 m.pointer_texcoord3f[1] = vertex3f;
2263 m.texmatrix[1] = r_shadow_entitytolight;
2265 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2266 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2269 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2271 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2273 // 2/0/0/2 3D combine blendsquare path
2274 memset(&m, 0, sizeof(m));
2275 m.pointer_vertex = vertex3f;
2276 m.tex[0] = R_GetTexture(bumptexture);
2277 m.pointer_texcoord[0] = texcoord2f;
2278 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2279 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2280 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2281 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2283 GL_ColorMask(0,0,0,1);
2284 // this squares the result
2285 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2286 GL_LockArrays(firstvertex, numvertices);
2287 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2288 GL_LockArrays(0, 0);
2290 c_rt_lighttris += numtriangles;
2292 memset(&m, 0, sizeof(m));
2293 m.pointer_vertex = vertex3f;
2295 GL_LockArrays(firstvertex, numvertices);
2296 // square alpha in framebuffer a few times to make it shiny
2297 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2298 // these comments are a test run through this math for intensity 0.5
2299 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2300 // 0.25 * 0.25 = 0.0625 (this is another pass)
2301 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2302 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2304 c_rt_lighttris += numtriangles;
2305 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2307 c_rt_lighttris += numtriangles;
2308 GL_LockArrays(0, 0);
2310 memset(&m, 0, sizeof(m));
2311 m.pointer_vertex = vertex3f;
2312 m.tex[0] = R_GetTexture(glosstexture);
2313 m.pointer_texcoord[0] = texcoord2f;
2314 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2316 m.pointer_texcoord3f[1] = vertex3f;
2317 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2319 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2320 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2322 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2326 // 2/0/0/2/2 2D combine blendsquare path
2327 memset(&m, 0, sizeof(m));
2328 m.pointer_vertex = vertex3f;
2329 m.tex[0] = R_GetTexture(bumptexture);
2330 m.pointer_texcoord[0] = texcoord2f;
2331 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2332 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2333 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2334 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2336 GL_ColorMask(0,0,0,1);
2337 // this squares the result
2338 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2339 GL_LockArrays(firstvertex, numvertices);
2340 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2341 GL_LockArrays(0, 0);
2343 c_rt_lighttris += numtriangles;
2345 memset(&m, 0, sizeof(m));
2346 m.pointer_vertex = vertex3f;
2348 GL_LockArrays(firstvertex, numvertices);
2349 // square alpha in framebuffer a few times to make it shiny
2350 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2351 // these comments are a test run through this math for intensity 0.5
2352 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2353 // 0.25 * 0.25 = 0.0625 (this is another pass)
2354 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2355 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2357 c_rt_lighttris += numtriangles;
2358 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2360 c_rt_lighttris += numtriangles;
2361 GL_LockArrays(0, 0);
2363 memset(&m, 0, sizeof(m));
2364 m.pointer_vertex = vertex3f;
2365 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2367 m.pointer_texcoord3f[0] = vertex3f;
2368 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2370 m.pointer_texcoord[0] = varray_texcoord2f[0];
2371 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2373 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2375 m.pointer_texcoord3f[1] = vertex3f;
2376 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2378 m.pointer_texcoord[1] = varray_texcoord2f[1];
2379 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2382 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2383 GL_LockArrays(firstvertex, numvertices);
2384 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2385 GL_LockArrays(0, 0);
2387 c_rt_lighttris += numtriangles;
2389 memset(&m, 0, sizeof(m));
2390 m.pointer_vertex = vertex3f;
2391 m.tex[0] = R_GetTexture(glosstexture);
2392 m.pointer_texcoord[0] = texcoord2f;
2393 if (r_shadow_lightcubemap != r_texture_whitecube)
2395 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2397 m.pointer_texcoord3f[1] = vertex3f;
2398 m.texmatrix[1] = r_shadow_entitytolight;
2400 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2401 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2404 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2407 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2408 VectorScale(lightcolorbase, colorscale, color2);
2409 GL_LockArrays(firstvertex, numvertices);
2410 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2412 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2413 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2415 c_rt_lighttris += numtriangles;
2417 GL_LockArrays(0, 0);
2421 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
2423 // TODO: add direct pants/shirt rendering
2424 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2425 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
2426 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2427 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
2428 if (r_shadow_rtlight->ambientscale)
2430 GL_BlendFunc(GL_ONE, GL_ONE);
2431 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
2432 memset(&m, 0, sizeof(m));
2433 m.pointer_vertex = vertex3f;
2434 m.tex[0] = R_GetTexture(basetexture);
2435 m.pointer_texcoord[0] = texcoord2f;
2436 if (r_textureunits.integer >= 2)
2439 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2441 m.pointer_texcoord3f[1] = vertex3f;
2442 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2444 m.pointer_texcoord[1] = varray_texcoord2f[1];
2445 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2447 if (r_textureunits.integer >= 3)
2449 // Geforce3/Radeon class but not using dot3
2450 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2452 m.pointer_texcoord3f[2] = vertex3f;
2453 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2455 m.pointer_texcoord[2] = varray_texcoord2f[2];
2456 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2460 if (r_textureunits.integer >= 3)
2461 m.pointer_color = NULL;
2463 m.pointer_color = varray_color4f;
2465 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2467 color[0] = bound(0, color2[0], 1);
2468 color[1] = bound(0, color2[1], 1);
2469 color[2] = bound(0, color2[2], 1);
2470 if (r_textureunits.integer >= 3)
2471 GL_Color(color[0], color[1], color[2], 1);
2472 else if (r_textureunits.integer >= 2)
2473 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2475 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2476 GL_LockArrays(firstvertex, numvertices);
2477 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2478 GL_LockArrays(0, 0);
2480 c_rt_lighttris += numtriangles;
2483 if (r_shadow_rtlight->diffusescale)
2485 GL_BlendFunc(GL_ONE, GL_ONE);
2486 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
2487 memset(&m, 0, sizeof(m));
2488 m.pointer_vertex = vertex3f;
2489 m.pointer_color = varray_color4f;
2490 m.tex[0] = R_GetTexture(basetexture);
2491 m.pointer_texcoord[0] = texcoord2f;
2492 if (r_textureunits.integer >= 2)
2495 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2497 m.pointer_texcoord3f[1] = vertex3f;
2498 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2500 m.pointer_texcoord[1] = varray_texcoord2f[1];
2501 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2503 if (r_textureunits.integer >= 3)
2505 // Geforce3/Radeon class but not using dot3
2506 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2508 m.pointer_texcoord3f[2] = vertex3f;
2509 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2511 m.pointer_texcoord[2] = varray_texcoord2f[2];
2512 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2517 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2519 color[0] = bound(0, color2[0], 1);
2520 color[1] = bound(0, color2[1], 1);
2521 color[2] = bound(0, color2[2], 1);
2522 if (r_textureunits.integer >= 3)
2523 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2524 else if (r_textureunits.integer >= 2)
2525 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2527 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2528 GL_LockArrays(firstvertex, numvertices);
2529 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2530 GL_LockArrays(0, 0);
2532 c_rt_lighttris += numtriangles;
2538 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2542 R_RTLight_Uncompile(rtlight);
2543 memset(rtlight, 0, sizeof(*rtlight));
2545 VectorCopy(light->origin, rtlight->shadoworigin);
2546 VectorCopy(light->color, rtlight->color);
2547 rtlight->radius = light->radius;
2548 //rtlight->cullradius = rtlight->radius;
2549 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2550 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2551 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2552 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2553 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2554 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2555 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2556 rtlight->cubemapname[0] = 0;
2557 if (light->cubemapname[0])
2558 strcpy(rtlight->cubemapname, light->cubemapname);
2559 else if (light->cubemapnum > 0)
2560 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2561 rtlight->shadow = light->shadow;
2562 rtlight->corona = light->corona;
2563 rtlight->style = light->style;
2564 rtlight->isstatic = isstatic;
2565 rtlight->coronasizescale = light->coronasizescale;
2566 rtlight->ambientscale = light->ambientscale;
2567 rtlight->diffusescale = light->diffusescale;
2568 rtlight->specularscale = light->specularscale;
2569 rtlight->flags = light->flags;
2570 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2571 // ConcatScale won't work here because this needs to scale rotate and
2572 // translate, not just rotate
2573 scale = 1.0f / rtlight->radius;
2574 for (k = 0;k < 3;k++)
2575 for (j = 0;j < 4;j++)
2576 rtlight->matrix_worldtolight.m[k][j] *= scale;
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, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
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_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2708 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2709 vec_t relativeshadowradius;
2710 if (ent == r_refdef.worldentity)
2712 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2715 R_Mesh_Matrix(&ent->matrix);
2716 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2718 R_Mesh_VertexPointer(mesh->vertex3f);
2719 GL_LockArrays(0, mesh->numverts);
2720 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2722 // increment stencil if backface is behind depthbuffer
2723 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2724 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2725 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2726 c_rtcached_shadowmeshes++;
2727 c_rtcached_shadowtris += mesh->numtriangles;
2728 // decrement stencil if frontface is behind depthbuffer
2729 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2730 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2732 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2733 c_rtcached_shadowmeshes++;
2734 c_rtcached_shadowtris += mesh->numtriangles;
2735 GL_LockArrays(0, 0);
2738 else if (numsurfaces)
2740 R_Mesh_Matrix(&ent->matrix);
2741 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2746 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2747 relativeshadowradius = rtlight->radius / ent->scale;
2748 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2749 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2750 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2751 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2752 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2753 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2754 R_Mesh_Matrix(&ent->matrix);
2755 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2759 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2762 // set up properties for rendering light onto this entity
2763 r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2764 r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2765 r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2766 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2767 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2768 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2769 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2770 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2771 R_Mesh_Matrix(&ent->matrix);
2772 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2774 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2775 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2776 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2777 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2779 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2782 if (ent == r_refdef.worldentity)
2784 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2786 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2787 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, r_shadow_entitylightcolor, vec3_origin, vec3_origin, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular);
2790 ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2793 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2796 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2801 int numleafs, numsurfaces;
2802 int *leaflist, *surfacelist;
2804 int numlightentities;
2805 int numshadowentities;
2806 entity_render_t *lightentities[MAX_EDICTS];
2807 entity_render_t *shadowentities[MAX_EDICTS];
2809 // skip lights that don't light (corona only lights)
2810 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2813 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2814 VectorScale(rtlight->color, f, lightcolor);
2815 if (VectorLength2(lightcolor) < 0.01)
2818 if (rtlight->selected)
2820 f = 2 + sin(realtime * M_PI * 4.0);
2821 VectorScale(lightcolor, f, lightcolor);
2825 // loading is done before visibility checks because loading should happen
2826 // all at once at the start of a level, not when it stalls gameplay.
2827 // (especially important to benchmarks)
2829 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2830 R_RTLight_Compile(rtlight);
2832 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2834 // if the light box is offscreen, skip it
2835 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2838 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2840 // compiled light, world available and can receive realtime lighting
2841 // retrieve leaf information
2842 numleafs = rtlight->static_numleafs;
2843 leaflist = rtlight->static_leaflist;
2844 leafpvs = rtlight->static_leafpvs;
2845 numsurfaces = rtlight->static_numsurfaces;
2846 surfacelist = rtlight->static_surfacelist;
2848 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2850 // dynamic light, world available and can receive realtime lighting
2851 // calculate lit surfaces and leafs
2852 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
2853 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2854 leaflist = r_shadow_buffer_leaflist;
2855 leafpvs = r_shadow_buffer_leafpvs;
2856 surfacelist = r_shadow_buffer_surfacelist;
2857 // if the reduced leaf bounds are offscreen, skip it
2858 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2870 // check if light is illuminating any visible leafs
2873 for (i = 0;i < numleafs;i++)
2874 if (r_worldleafvisible[leaflist[i]])
2879 // set up a scissor rectangle for this light
2880 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2883 numlightentities = 0;
2885 lightentities[numlightentities++] = r_refdef.worldentity;
2886 numshadowentities = 0;
2888 shadowentities[numshadowentities++] = r_refdef.worldentity;
2889 if (r_drawentities.integer)
2891 for (i = 0;i < r_refdef.numentities;i++)
2893 entity_render_t *ent = r_refdef.entities[i];
2894 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2896 && !(ent->flags & RENDER_TRANSPARENT)
2897 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2899 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2900 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2901 shadowentities[numshadowentities++] = ent;
2902 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2903 lightentities[numlightentities++] = ent;
2908 // return if there's nothing at all to light
2909 if (!numlightentities)
2912 R_Shadow_Stage_ActiveLight(rtlight);
2916 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2919 R_Shadow_Stage_StencilShadowVolumes();
2920 for (i = 0;i < numshadowentities;i++)
2921 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2924 if (numlightentities && !visible)
2926 R_Shadow_Stage_Lighting(usestencil);
2927 for (i = 0;i < numlightentities;i++)
2928 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2931 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2933 R_Shadow_Stage_VisibleShadowVolumes();
2934 for (i = 0;i < numshadowentities;i++)
2935 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2938 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2940 R_Shadow_Stage_VisibleLighting(usestencil);
2941 for (i = 0;i < numlightentities;i++)
2942 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2946 void R_ShadowVolumeLighting(qboolean visible)
2951 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2952 R_Shadow_EditLights_Reload_f();
2954 R_Shadow_Stage_Begin();
2956 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2957 if (r_shadow_debuglight.integer >= 0)
2959 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2960 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2961 R_DrawRTLight(&light->rtlight, visible);
2964 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2965 if (light->flags & flag)
2966 R_DrawRTLight(&light->rtlight, visible);
2968 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2969 R_DrawRTLight(&light->rtlight, visible);
2971 R_Shadow_Stage_End();
2974 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2975 typedef struct suffixinfo_s
2978 qboolean flipx, flipy, flipdiagonal;
2981 static suffixinfo_t suffix[3][6] =
2984 {"px", false, false, false},
2985 {"nx", false, false, false},
2986 {"py", false, false, false},
2987 {"ny", false, false, false},
2988 {"pz", false, false, false},
2989 {"nz", false, false, false}
2992 {"posx", false, false, false},
2993 {"negx", false, false, false},
2994 {"posy", false, false, false},
2995 {"negy", false, false, false},
2996 {"posz", false, false, false},
2997 {"negz", false, false, false}
3000 {"rt", true, false, true},
3001 {"lf", false, true, true},
3002 {"ft", true, true, false},
3003 {"bk", false, false, false},
3004 {"up", true, false, true},
3005 {"dn", true, false, true}
3009 static int componentorder[4] = {0, 1, 2, 3};
3011 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3013 int i, j, cubemapsize;
3014 qbyte *cubemappixels, *image_rgba;
3015 rtexture_t *cubemaptexture;
3017 // must start 0 so the first loadimagepixels has no requested width/height
3019 cubemappixels = NULL;
3020 cubemaptexture = NULL;
3021 // keep trying different suffix groups (posx, px, rt) until one loads
3022 for (j = 0;j < 3 && !cubemappixels;j++)
3024 // load the 6 images in the suffix group
3025 for (i = 0;i < 6;i++)
3027 // generate an image name based on the base and and suffix
3028 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3030 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3032 // an image loaded, make sure width and height are equal
3033 if (image_width == image_height)
3035 // if this is the first image to load successfully, allocate the cubemap memory
3036 if (!cubemappixels && image_width >= 1)
3038 cubemapsize = image_width;
3039 // note this clears to black, so unavailable sides are black
3040 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3042 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3044 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);
3047 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3049 Mem_Free(image_rgba);
3053 // if a cubemap loaded, upload it
3056 if (!r_shadow_filters_texturepool)
3057 r_shadow_filters_texturepool = R_AllocTexturePool();
3058 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3059 Mem_Free(cubemappixels);
3063 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3064 for (j = 0;j < 3;j++)
3065 for (i = 0;i < 6;i++)
3066 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3067 Con_Print(" and was unable to find any of them.\n");
3069 return cubemaptexture;
3072 rtexture_t *R_Shadow_Cubemap(const char *basename)
3075 for (i = 0;i < numcubemaps;i++)
3076 if (!strcasecmp(cubemaps[i].basename, basename))
3077 return cubemaps[i].texture;
3078 if (i >= MAX_CUBEMAPS)
3079 return r_texture_whitecube;
3081 strcpy(cubemaps[i].basename, basename);
3082 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3083 return cubemaps[i].texture;
3086 void R_Shadow_FreeCubemaps(void)
3089 R_FreeTexturePool(&r_shadow_filters_texturepool);
3092 dlight_t *R_Shadow_NewWorldLight(void)
3095 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3096 light->next = r_shadow_worldlightchain;
3097 r_shadow_worldlightchain = light;
3101 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)
3103 VectorCopy(origin, light->origin);
3104 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3105 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3106 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3107 light->color[0] = max(color[0], 0);
3108 light->color[1] = max(color[1], 0);
3109 light->color[2] = max(color[2], 0);
3110 light->radius = max(radius, 0);
3111 light->style = style;
3112 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3114 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3117 light->shadow = shadowenable;
3118 light->corona = corona;
3121 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3122 light->coronasizescale = coronasizescale;
3123 light->ambientscale = ambientscale;
3124 light->diffusescale = diffusescale;
3125 light->specularscale = specularscale;
3126 light->flags = flags;
3127 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3129 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3132 void R_Shadow_FreeWorldLight(dlight_t *light)
3134 dlight_t **lightpointer;
3135 R_RTLight_Uncompile(&light->rtlight);
3136 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3137 if (*lightpointer != light)
3138 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3139 *lightpointer = light->next;
3143 void R_Shadow_ClearWorldLights(void)
3145 while (r_shadow_worldlightchain)
3146 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3147 r_shadow_selectedlight = NULL;
3148 R_Shadow_FreeCubemaps();
3151 void R_Shadow_SelectLight(dlight_t *light)
3153 if (r_shadow_selectedlight)
3154 r_shadow_selectedlight->selected = false;
3155 r_shadow_selectedlight = light;
3156 if (r_shadow_selectedlight)
3157 r_shadow_selectedlight->selected = true;
3160 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3162 float scale = r_editlights_cursorgrid.value * 0.5f;
3163 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);
3166 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3169 const dlight_t *light;
3172 if (light->selected)
3173 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3176 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);
3179 void R_Shadow_DrawLightSprites(void)
3185 for (i = 0;i < 5;i++)
3187 lighttextures[i] = NULL;
3188 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3189 lighttextures[i] = pic->tex;
3192 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3193 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3194 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3197 void R_Shadow_SelectLightInView(void)
3199 float bestrating, rating, temp[3];
3200 dlight_t *best, *light;
3203 for (light = r_shadow_worldlightchain;light;light = light->next)
3205 VectorSubtract(light->origin, r_vieworigin, temp);
3206 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3209 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3210 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3212 bestrating = rating;
3217 R_Shadow_SelectLight(best);
3220 void R_Shadow_LoadWorldLights(void)
3222 int n, a, style, shadow, flags;
3223 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3224 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3225 if (r_refdef.worldmodel == NULL)
3227 Con_Print("No map loaded.\n");
3230 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3231 strlcat (name, ".rtlights", sizeof (name));
3232 lightsstring = FS_LoadFile(name, tempmempool, false);
3242 for (;COM_Parse(t, true) && strcmp(
3243 if (COM_Parse(t, true))
3245 if (com_token[0] == '!')
3248 origin[0] = atof(com_token+1);
3251 origin[0] = atof(com_token);
3256 while (*s && *s != '\n' && *s != '\r')
3262 // check for modifier flags
3269 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);
3272 flags = LIGHTFLAG_REALTIMEMODE;
3280 coronasizescale = 0.25f;
3282 VectorClear(angles);
3285 if (a < 9 || !strcmp(cubemapname, "\"\""))
3287 // remove quotes on cubemapname
3288 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3290 cubemapname[strlen(cubemapname)-1] = 0;
3291 strcpy(cubemapname, cubemapname + 1);
3295 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);
3298 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3299 radius *= r_editlights_rtlightssizescale.value;
3300 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3308 Con_Printf("invalid rtlights file \"%s\"\n", name);
3309 Mem_Free(lightsstring);
3313 void R_Shadow_SaveWorldLights(void)
3316 int bufchars, bufmaxchars;
3318 char name[MAX_QPATH];
3320 if (!r_shadow_worldlightchain)
3322 if (r_refdef.worldmodel == NULL)
3324 Con_Print("No map loaded.\n");
3327 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3328 strlcat (name, ".rtlights", sizeof (name));
3329 bufchars = bufmaxchars = 0;
3331 for (light = r_shadow_worldlightchain;light;light = light->next)
3333 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3334 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);
3335 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3336 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]);
3338 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);
3339 if (bufchars + (int) strlen(line) > bufmaxchars)
3341 bufmaxchars = bufchars + strlen(line) + 2048;
3343 buf = Mem_Alloc(tempmempool, bufmaxchars);
3347 memcpy(buf, oldbuf, bufchars);
3353 memcpy(buf + bufchars, line, strlen(line));
3354 bufchars += strlen(line);
3358 FS_WriteFile(name, buf, bufchars);
3363 void R_Shadow_LoadLightsFile(void)
3366 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3367 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3368 if (r_refdef.worldmodel == NULL)
3370 Con_Print("No map loaded.\n");
3373 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3374 strlcat (name, ".lights", sizeof (name));
3375 lightsstring = FS_LoadFile(name, tempmempool, false);
3383 while (*s && *s != '\n' && *s != '\r')
3389 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);
3393 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);
3396 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3397 radius = bound(15, radius, 4096);
3398 VectorScale(color, (2.0f / (8388608.0f)), color);
3399 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3407 Con_Printf("invalid lights file \"%s\"\n", name);
3408 Mem_Free(lightsstring);
3412 // tyrlite/hmap2 light types in the delay field
3413 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3415 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3417 int entnum, style, islight, skin, pflags, effects, type, n;
3420 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3421 char key[256], value[1024];
3423 if (r_refdef.worldmodel == NULL)
3425 Con_Print("No map loaded.\n");
3428 // try to load a .ent file first
3429 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3430 strlcat (key, ".ent", sizeof (key));
3431 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3432 // and if that is not found, fall back to the bsp file entity string
3434 data = r_refdef.worldmodel->brush.entities;
3437 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3439 type = LIGHTTYPE_MINUSX;
3440 origin[0] = origin[1] = origin[2] = 0;
3441 originhack[0] = originhack[1] = originhack[2] = 0;
3442 angles[0] = angles[1] = angles[2] = 0;
3443 color[0] = color[1] = color[2] = 1;
3444 light[0] = light[1] = light[2] = 1;light[3] = 300;
3445 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3455 if (!COM_ParseToken(&data, false))
3457 if (com_token[0] == '}')
3458 break; // end of entity
3459 if (com_token[0] == '_')
3460 strcpy(key, com_token + 1);
3462 strcpy(key, com_token);
3463 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3464 key[strlen(key)-1] = 0;
3465 if (!COM_ParseToken(&data, false))
3467 strcpy(value, com_token);
3469 // now that we have the key pair worked out...
3470 if (!strcmp("light", key))
3472 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3476 light[0] = vec[0] * (1.0f / 256.0f);
3477 light[1] = vec[0] * (1.0f / 256.0f);
3478 light[2] = vec[0] * (1.0f / 256.0f);
3484 light[0] = vec[0] * (1.0f / 255.0f);
3485 light[1] = vec[1] * (1.0f / 255.0f);
3486 light[2] = vec[2] * (1.0f / 255.0f);
3490 else if (!strcmp("delay", key))
3492 else if (!strcmp("origin", key))
3493 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3494 else if (!strcmp("angle", key))
3495 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3496 else if (!strcmp("angles", key))
3497 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3498 else if (!strcmp("color", key))
3499 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3500 else if (!strcmp("wait", key))
3501 fadescale = atof(value);
3502 else if (!strcmp("classname", key))
3504 if (!strncmp(value, "light", 5))
3507 if (!strcmp(value, "light_fluoro"))
3512 overridecolor[0] = 1;
3513 overridecolor[1] = 1;
3514 overridecolor[2] = 1;
3516 if (!strcmp(value, "light_fluorospark"))
3521 overridecolor[0] = 1;
3522 overridecolor[1] = 1;
3523 overridecolor[2] = 1;
3525 if (!strcmp(value, "light_globe"))
3530 overridecolor[0] = 1;
3531 overridecolor[1] = 0.8;
3532 overridecolor[2] = 0.4;
3534 if (!strcmp(value, "light_flame_large_yellow"))
3539 overridecolor[0] = 1;
3540 overridecolor[1] = 0.5;
3541 overridecolor[2] = 0.1;
3543 if (!strcmp(value, "light_flame_small_yellow"))
3548 overridecolor[0] = 1;
3549 overridecolor[1] = 0.5;
3550 overridecolor[2] = 0.1;
3552 if (!strcmp(value, "light_torch_small_white"))
3557 overridecolor[0] = 1;
3558 overridecolor[1] = 0.5;
3559 overridecolor[2] = 0.1;
3561 if (!strcmp(value, "light_torch_small_walltorch"))
3566 overridecolor[0] = 1;
3567 overridecolor[1] = 0.5;
3568 overridecolor[2] = 0.1;
3572 else if (!strcmp("style", key))
3573 style = atoi(value);
3574 else if (r_refdef.worldmodel->type == mod_brushq3)
3576 if (!strcmp("scale", key))
3577 lightscale = atof(value);
3578 if (!strcmp("fade", key))
3579 fadescale = atof(value);
3581 else if (!strcmp("skin", key))
3582 skin = (int)atof(value);
3583 else if (!strcmp("pflags", key))
3584 pflags = (int)atof(value);
3585 else if (!strcmp("effects", key))
3586 effects = (int)atof(value);
3590 if (lightscale <= 0)
3594 if (color[0] == color[1] && color[0] == color[2])
3596 color[0] *= overridecolor[0];
3597 color[1] *= overridecolor[1];
3598 color[2] *= overridecolor[2];
3600 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3601 color[0] = color[0] * light[0];
3602 color[1] = color[1] * light[1];
3603 color[2] = color[2] * light[2];
3606 case LIGHTTYPE_MINUSX:
3608 case LIGHTTYPE_RECIPX:
3610 VectorScale(color, (1.0f / 16.0f), color);
3612 case LIGHTTYPE_RECIPXX:
3614 VectorScale(color, (1.0f / 16.0f), color);
3617 case LIGHTTYPE_NONE:
3621 case LIGHTTYPE_MINUSXX:
3624 VectorAdd(origin, originhack, origin);
3626 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);
3629 Mem_Free(entfiledata);
3633 void R_Shadow_SetCursorLocationForView(void)
3636 vec3_t dest, endpos;
3638 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3639 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3640 if (trace.fraction < 1)
3642 dist = trace.fraction * r_editlights_cursordistance.value;
3643 push = r_editlights_cursorpushback.value;
3647 VectorMA(trace.endpos, push, r_viewforward, endpos);
3648 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3650 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3651 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3652 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3655 void R_Shadow_UpdateWorldLightSelection(void)
3657 if (r_editlights.integer)
3659 R_Shadow_SetCursorLocationForView();
3660 R_Shadow_SelectLightInView();
3661 R_Shadow_DrawLightSprites();
3664 R_Shadow_SelectLight(NULL);
3667 void R_Shadow_EditLights_Clear_f(void)
3669 R_Shadow_ClearWorldLights();
3672 void R_Shadow_EditLights_Reload_f(void)
3674 if (!r_refdef.worldmodel)
3676 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3677 R_Shadow_ClearWorldLights();
3678 R_Shadow_LoadWorldLights();
3679 if (r_shadow_worldlightchain == NULL)
3681 R_Shadow_LoadLightsFile();
3682 if (r_shadow_worldlightchain == NULL)
3683 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3687 void R_Shadow_EditLights_Save_f(void)
3689 if (!r_refdef.worldmodel)
3691 R_Shadow_SaveWorldLights();
3694 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3696 R_Shadow_ClearWorldLights();
3697 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3700 void R_Shadow_EditLights_ImportLightsFile_f(void)
3702 R_Shadow_ClearWorldLights();
3703 R_Shadow_LoadLightsFile();
3706 void R_Shadow_EditLights_Spawn_f(void)
3709 if (!r_editlights.integer)
3711 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3714 if (Cmd_Argc() != 1)
3716 Con_Print("r_editlights_spawn does not take parameters\n");
3719 color[0] = color[1] = color[2] = 1;
3720 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3723 void R_Shadow_EditLights_Edit_f(void)
3725 vec3_t origin, angles, color;
3726 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3727 int style, shadows, flags, normalmode, realtimemode;
3728 char cubemapname[1024];
3729 if (!r_editlights.integer)
3731 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3734 if (!r_shadow_selectedlight)
3736 Con_Print("No selected light.\n");
3739 VectorCopy(r_shadow_selectedlight->origin, origin);
3740 VectorCopy(r_shadow_selectedlight->angles, angles);
3741 VectorCopy(r_shadow_selectedlight->color, color);
3742 radius = r_shadow_selectedlight->radius;
3743 style = r_shadow_selectedlight->style;
3744 if (r_shadow_selectedlight->cubemapname)
3745 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3748 shadows = r_shadow_selectedlight->shadow;
3749 corona = r_shadow_selectedlight->corona;
3750 coronasizescale = r_shadow_selectedlight->coronasizescale;
3751 ambientscale = r_shadow_selectedlight->ambientscale;
3752 diffusescale = r_shadow_selectedlight->diffusescale;
3753 specularscale = r_shadow_selectedlight->specularscale;
3754 flags = r_shadow_selectedlight->flags;
3755 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3756 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3757 if (!strcmp(Cmd_Argv(1), "origin"))
3759 if (Cmd_Argc() != 5)
3761 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3764 origin[0] = atof(Cmd_Argv(2));
3765 origin[1] = atof(Cmd_Argv(3));
3766 origin[2] = atof(Cmd_Argv(4));
3768 else if (!strcmp(Cmd_Argv(1), "originx"))
3770 if (Cmd_Argc() != 3)
3772 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3775 origin[0] = atof(Cmd_Argv(2));
3777 else if (!strcmp(Cmd_Argv(1), "originy"))
3779 if (Cmd_Argc() != 3)
3781 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3784 origin[1] = atof(Cmd_Argv(2));
3786 else if (!strcmp(Cmd_Argv(1), "originz"))
3788 if (Cmd_Argc() != 3)
3790 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3793 origin[2] = atof(Cmd_Argv(2));
3795 else if (!strcmp(Cmd_Argv(1), "move"))
3797 if (Cmd_Argc() != 5)
3799 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3802 origin[0] += atof(Cmd_Argv(2));
3803 origin[1] += atof(Cmd_Argv(3));
3804 origin[2] += atof(Cmd_Argv(4));
3806 else if (!strcmp(Cmd_Argv(1), "movex"))
3808 if (Cmd_Argc() != 3)
3810 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3813 origin[0] += atof(Cmd_Argv(2));
3815 else if (!strcmp(Cmd_Argv(1), "movey"))
3817 if (Cmd_Argc() != 3)
3819 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3822 origin[1] += atof(Cmd_Argv(2));
3824 else if (!strcmp(Cmd_Argv(1), "movez"))
3826 if (Cmd_Argc() != 3)
3828 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3831 origin[2] += atof(Cmd_Argv(2));
3833 else if (!strcmp(Cmd_Argv(1), "angles"))
3835 if (Cmd_Argc() != 5)
3837 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3840 angles[0] = atof(Cmd_Argv(2));
3841 angles[1] = atof(Cmd_Argv(3));
3842 angles[2] = atof(Cmd_Argv(4));
3844 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3846 if (Cmd_Argc() != 3)
3848 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3851 angles[0] = atof(Cmd_Argv(2));
3853 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3855 if (Cmd_Argc() != 3)
3857 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3860 angles[1] = atof(Cmd_Argv(2));
3862 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3864 if (Cmd_Argc() != 3)
3866 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3869 angles[2] = atof(Cmd_Argv(2));
3871 else if (!strcmp(Cmd_Argv(1), "color"))
3873 if (Cmd_Argc() != 5)
3875 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3878 color[0] = atof(Cmd_Argv(2));
3879 color[1] = atof(Cmd_Argv(3));
3880 color[2] = atof(Cmd_Argv(4));
3882 else if (!strcmp(Cmd_Argv(1), "radius"))
3884 if (Cmd_Argc() != 3)
3886 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3889 radius = atof(Cmd_Argv(2));
3891 else if (!strcmp(Cmd_Argv(1), "style"))
3893 if (Cmd_Argc() != 3)
3895 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3898 style = atoi(Cmd_Argv(2));
3900 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3904 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3907 if (Cmd_Argc() == 3)
3908 strcpy(cubemapname, Cmd_Argv(2));
3912 else if (!strcmp(Cmd_Argv(1), "shadows"))
3914 if (Cmd_Argc() != 3)
3916 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3919 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3921 else if (!strcmp(Cmd_Argv(1), "corona"))
3923 if (Cmd_Argc() != 3)
3925 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3928 corona = atof(Cmd_Argv(2));
3930 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3932 if (Cmd_Argc() != 3)
3934 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3937 coronasizescale = atof(Cmd_Argv(2));
3939 else if (!strcmp(Cmd_Argv(1), "ambient"))
3941 if (Cmd_Argc() != 3)
3943 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3946 ambientscale = atof(Cmd_Argv(2));
3948 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3950 if (Cmd_Argc() != 3)
3952 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3955 diffusescale = atof(Cmd_Argv(2));
3957 else if (!strcmp(Cmd_Argv(1), "specular"))
3959 if (Cmd_Argc() != 3)
3961 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3964 specularscale = atof(Cmd_Argv(2));
3966 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3968 if (Cmd_Argc() != 3)
3970 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3973 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3975 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3977 if (Cmd_Argc() != 3)
3979 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3982 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3986 Con_Print("usage: r_editlights_edit [property] [value]\n");
3987 Con_Print("Selected light's properties:\n");
3988 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3989 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3990 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3991 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3992 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3993 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3994 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3995 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3996 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3997 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3998 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3999 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4000 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4001 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4004 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4005 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4008 void R_Shadow_EditLights_EditAll_f(void)
4012 if (!r_editlights.integer)
4014 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4018 for (light = r_shadow_worldlightchain;light;light = light->next)
4020 R_Shadow_SelectLight(light);
4021 R_Shadow_EditLights_Edit_f();
4025 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4027 int lightnumber, lightcount;
4031 if (!r_editlights.integer)
4037 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4038 if (light == r_shadow_selectedlight)
4039 lightnumber = lightcount;
4040 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;
4041 if (r_shadow_selectedlight == NULL)
4043 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4044 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;
4045 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;
4046 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;
4047 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4048 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4049 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4050 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;
4051 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4052 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4053 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4054 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4055 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4056 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;
4057 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;
4060 void R_Shadow_EditLights_ToggleShadow_f(void)
4062 if (!r_editlights.integer)
4064 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4067 if (!r_shadow_selectedlight)
4069 Con_Print("No selected light.\n");
4072 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);
4075 void R_Shadow_EditLights_ToggleCorona_f(void)
4077 if (!r_editlights.integer)
4079 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4082 if (!r_shadow_selectedlight)
4084 Con_Print("No selected light.\n");
4087 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);
4090 void R_Shadow_EditLights_Remove_f(void)
4092 if (!r_editlights.integer)
4094 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4097 if (!r_shadow_selectedlight)
4099 Con_Print("No selected light.\n");
4102 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4103 r_shadow_selectedlight = NULL;
4106 void R_Shadow_EditLights_Help_f(void)
4109 "Documentation on r_editlights system:\n"
4111 "r_editlights : enable/disable editing mode\n"
4112 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4113 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4114 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4115 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4116 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4117 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4118 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4120 "r_editlights_help : this help\n"
4121 "r_editlights_clear : remove all lights\n"
4122 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4123 "r_editlights_save : save to .rtlights file\n"
4124 "r_editlights_spawn : create a light with default settings\n"
4125 "r_editlights_edit command : edit selected light - more documentation below\n"
4126 "r_editlights_remove : remove selected light\n"
4127 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4128 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4129 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4131 "origin x y z : set light location\n"
4132 "originx x: set x component of light location\n"
4133 "originy y: set y component of light location\n"
4134 "originz z: set z component of light location\n"
4135 "move x y z : adjust light location\n"
4136 "movex x: adjust x component of light location\n"
4137 "movey y: adjust y component of light location\n"
4138 "movez z: adjust z component of light location\n"
4139 "angles x y z : set light angles\n"
4140 "anglesx x: set x component of light angles\n"
4141 "anglesy y: set y component of light angles\n"
4142 "anglesz z: set z component of light angles\n"
4143 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4144 "radius radius : set radius (size) of light\n"
4145 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4146 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4147 "shadows 1/0 : turn on/off shadows\n"
4148 "corona n : set corona intensity\n"
4149 "coronasize n : set corona size (0-1)\n"
4150 "ambient n : set ambient intensity (0-1)\n"
4151 "diffuse n : set diffuse intensity (0-1)\n"
4152 "specular n : set specular intensity (0-1)\n"
4153 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4154 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4155 "<nothing> : print light properties to console\n"
4159 void R_Shadow_EditLights_CopyInfo_f(void)
4161 if (!r_editlights.integer)
4163 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4166 if (!r_shadow_selectedlight)
4168 Con_Print("No selected light.\n");
4171 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4172 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4173 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4174 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4175 if (r_shadow_selectedlight->cubemapname)
4176 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4178 r_shadow_bufferlight.cubemapname[0] = 0;
4179 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4180 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4181 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4182 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4183 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4184 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4185 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4188 void R_Shadow_EditLights_PasteInfo_f(void)
4190 if (!r_editlights.integer)
4192 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4195 if (!r_shadow_selectedlight)
4197 Con_Print("No selected light.\n");
4200 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);
4203 void R_Shadow_EditLights_Init(void)
4205 Cvar_RegisterVariable(&r_editlights);
4206 Cvar_RegisterVariable(&r_editlights_cursordistance);
4207 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4208 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4209 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4210 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4211 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4212 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4213 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4214 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4215 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4216 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4217 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4218 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4219 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4220 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4221 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4222 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4223 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4224 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4225 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4226 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);