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 to hopefully avoid the Creative Labs patent on Carmack's Reverse,
17 we use a biased stencil clear of 128 (which also negates the need for the
18 stencil wrap extension), we draw the frontfaces first and backfaces second
19 (decrement, increment), and we redefine the DepthFunc to zpass when behind of
20 surfaces and zfail when infront (this means zpass is decr/incr during volume
21 rendering, not zfail).
24 This algorithm may be covered by Creative's patent (US Patent #6384822)
25 on Carmack's Reverse paper (which I have not read), however that patent
26 seems to be about drawing a stencil shadow from a model in an otherwise
27 unshadowed scene, where as realtime lighting technology draws light where
28 shadows do not lie, additionally the stencil clear, zfail/zpass rules and
29 incr/decr order are different in this implementation.
33 Terminology: Stencil Light Volume (sometimes called Light Volumes)
34 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
35 areas in shadow it contains the areas in light, this can only be built
36 quickly for certain limited cases (such as portal visibility from a point),
37 but is quite useful for some effects (sunlight coming from sky polygons is
38 one possible example, translucent occluders is another example).
42 Terminology: Optimized Stencil Shadow Volume
43 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
44 no duplicate coverage of areas (no need to shadow an area twice), often this
45 greatly improves performance but is an operation too costly to use on moving
46 lights (however completely optimal Stencil Light Volumes can be constructed
51 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
52 Per pixel evaluation of lighting equations, at a bare minimum this involves
53 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
54 vector and surface normal, using a texture of the surface bumps, called a
55 NormalMap) if supported by hardware; in our case there is support for cards
56 which are incapable of DOT3, the quality is quite poor however. Additionally
57 it is desirable to have specular evaluation per pixel, per vertex
58 normalization of specular halfangle vectors causes noticable distortion but
59 is unavoidable on hardware without GL_ARB_fragment_program or
60 GL_ARB_fragment_shader.
64 Terminology: Normalization CubeMap
65 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
66 encoded as RGB colors) for any possible direction, this technique allows per
67 pixel calculation of incidence vector for per pixel lighting purposes, which
68 would not otherwise be possible per pixel without GL_ARB_fragment_program or
69 GL_ARB_fragment_shader.
73 Terminology: 2D+1D Attenuation Texturing
74 A very crude approximation of light attenuation with distance which results
75 in cylindrical light shapes which fade vertically as a streak (some games
76 such as Doom3 allow this to be rotated to be less noticable in specific
77 cases), the technique is simply modulating lighting by two 2D textures (which
78 can be the same) on different axes of projection (XY and Z, typically), this
79 is the second best technique available without 3D Attenuation Texturing,
80 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
84 Terminology: 2D+1D Inverse Attenuation Texturing
85 A clever method described in papers on the Abducted engine, this has a squared
86 distance texture (bright on the outside, black in the middle), which is used
87 twice using GL_ADD blending, the result of this is used in an inverse modulate
88 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
89 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
94 Terminology: 3D Attenuation Texturing
95 A slightly crude approximation of light attenuation with distance, its flaws
96 are limited radius and resolution (performance tradeoffs).
100 Terminology: 3D Attenuation-Normalization Texturing
101 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
102 vectors shorter the lighting becomes darker, a very effective optimization of
103 diffuse lighting if 3D Attenuation Textures are already used.
107 Terminology: Light Cubemap Filtering
108 A technique for modeling non-uniform light distribution according to
109 direction, for example a lantern may use a cubemap to describe the light
110 emission pattern of the cage around the lantern (as well as soot buildup
111 discoloring the light in certain areas), often also used for softened grate
112 shadows and light shining through a stained glass window (done crudely by
113 texturing the lighting with a cubemap), another good example would be a disco
114 light. This technique is used heavily in many games (Doom3 does not support
119 Terminology: Light Projection Filtering
120 A technique for modeling shadowing of light passing through translucent
121 surfaces, allowing stained glass windows and other effects to be done more
122 elegantly than possible with Light Cubemap Filtering by applying an occluder
123 texture to the lighting combined with a stencil light volume to limit the lit
124 area, this technique is used by Doom3 for spotlights and flashlights, among
125 other things, this can also be used more generally to render light passing
126 through multiple translucent occluders in a scene (using a light volume to
127 describe the area beyond the occluder, and thus mask off rendering of all
132 Terminology: Doom3 Lighting
133 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
134 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
135 demonstrated by the game Doom3.
138 #include "quakedef.h"
139 #include "r_shadow.h"
140 #include "cl_collision.h"
144 extern void R_Shadow_EditLights_Init(void);
146 typedef enum r_shadowstage_e
149 R_SHADOWSTAGE_STENCIL,
150 R_SHADOWSTAGE_STENCILTWOSIDE,
151 R_SHADOWSTAGE_LIGHT_VERTEX,
152 R_SHADOWSTAGE_LIGHT_DOT3,
153 R_SHADOWSTAGE_LIGHT_GLSL,
154 R_SHADOWSTAGE_VISIBLEVOLUMES,
155 R_SHADOWSTAGE_VISIBLELIGHTING,
159 r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
161 mempool_t *r_shadow_mempool;
163 int maxshadowelements;
177 int r_shadow_buffer_numleafpvsbytes;
178 qbyte *r_shadow_buffer_leafpvs;
179 int *r_shadow_buffer_leaflist;
181 int r_shadow_buffer_numsurfacepvsbytes;
182 qbyte *r_shadow_buffer_surfacepvs;
183 int *r_shadow_buffer_surfacelist;
185 rtexturepool_t *r_shadow_texturepool;
186 rtexture_t *r_shadow_attenuation2dtexture;
187 rtexture_t *r_shadow_attenuation3dtexture;
189 // lights are reloaded when this changes
190 char r_shadow_mapname[MAX_QPATH];
192 // used only for light filters (cubemaps)
193 rtexturepool_t *r_shadow_filters_texturepool;
195 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
196 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
197 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
198 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
199 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
200 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
201 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
202 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
203 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
204 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
205 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
206 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
207 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
208 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
209 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
210 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
211 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
212 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
213 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
214 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
215 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
216 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
217 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
218 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
219 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
220 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
221 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
222 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
223 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
224 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
225 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
226 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
227 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
228 cvar_t r_editlights = {0, "r_editlights", "0"};
229 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
230 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
231 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
232 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
233 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
234 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
235 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
237 float r_shadow_attenpower, r_shadow_attenscale;
239 rtlight_t *r_shadow_compilingrtlight;
240 dlight_t *r_shadow_worldlightchain;
241 dlight_t *r_shadow_selectedlight;
242 dlight_t r_shadow_bufferlight;
243 vec3_t r_editlights_cursorlocation;
245 rtexture_t *lighttextures[5];
247 extern int con_vislines;
249 typedef struct cubemapinfo_s
256 #define MAX_CUBEMAPS 256
257 static int numcubemaps;
258 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
260 #define SHADERPERMUTATION_SPECULAR (1<<0)
261 #define SHADERPERMUTATION_FOG (1<<1)
262 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
263 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
264 #define SHADERPERMUTATION_COUNT (1<<4)
266 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
268 void R_Shadow_UncompileWorldLights(void);
269 void R_Shadow_ClearWorldLights(void);
270 void R_Shadow_SaveWorldLights(void);
271 void R_Shadow_LoadWorldLights(void);
272 void R_Shadow_LoadLightsFile(void);
273 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
274 void R_Shadow_EditLights_Reload_f(void);
275 void R_Shadow_ValidateCvars(void);
276 static void R_Shadow_MakeTextures(void);
277 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
279 const char *builtinshader_light_vert =
280 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
281 "// written by Forest 'LordHavoc' Hale\n"
283 "uniform vec3 LightPosition;\n"
285 "varying vec2 TexCoord;\n"
286 "varying vec3 CubeVector;\n"
287 "varying vec3 LightVector;\n"
289 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
290 "uniform vec3 EyePosition;\n"
291 "varying vec3 EyeVector;\n"
294 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
298 " // copy the surface texcoord\n"
299 " TexCoord = gl_MultiTexCoord0.st;\n"
301 " // transform vertex position into light attenuation/cubemap space\n"
302 " // (-1 to +1 across the light box)\n"
303 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
305 " // transform unnormalized light direction into tangent space\n"
306 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
307 " // normalize it per pixel)\n"
308 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
309 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
310 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
311 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
313 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
314 " // transform unnormalized eye direction into tangent space\n"
315 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
316 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
317 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
318 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
321 " // transform vertex to camera space, using ftransform to match non-VS\n"
323 " gl_Position = ftransform();\n"
327 const char *builtinshader_light_frag =
328 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
329 "// written by Forest 'LordHavoc' Hale\n"
331 "uniform vec3 LightColor;\n"
333 "#ifdef USEOFFSETMAPPING\n"
334 "uniform float OffsetMapping_Scale;\n"
335 "uniform float OffsetMapping_Bias;\n"
337 "#ifdef USESPECULAR\n"
338 "uniform float SpecularPower;\n"
341 "uniform float FogRangeRecip;\n"
343 "uniform float AmbientScale;\n"
344 "uniform float DiffuseScale;\n"
345 "#ifdef USESPECULAR\n"
346 "uniform float SpecularScale;\n"
349 "uniform sampler2D Texture_Normal;\n"
350 "uniform sampler2D Texture_Color;\n"
351 "#ifdef USESPECULAR\n"
352 "uniform sampler2D Texture_Gloss;\n"
354 "#ifdef USECUBEFILTER\n"
355 "uniform samplerCube Texture_Cube;\n"
358 "uniform sampler2D Texture_FogMask;\n"
361 "varying vec2 TexCoord;\n"
362 "varying vec3 CubeVector;\n"
363 "varying vec3 LightVector;\n"
364 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
365 "varying vec3 EyeVector;\n"
372 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
373 " // center and sharp falloff at the edge, this is about the most efficient\n"
374 " // we can get away with as far as providing illumination.\n"
376 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
377 " // provide significant illumination, large = slow = pain.\n"
378 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
382 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
385 "#ifdef USEOFFSETMAPPING\n"
386 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
387 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
388 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
389 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
390 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
391 "#define TexCoord TexCoordOffset\n"
394 " // get the texels - with a blendmap we'd need to blend multiple here\n"
395 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
396 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
397 "#ifdef USESPECULAR\n"
398 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
401 " // calculate shading\n"
402 " vec3 diffusenormal = normalize(LightVector);\n"
403 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
404 "#ifdef USESPECULAR\n"
405 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
408 "#ifdef USECUBEFILTER\n"
409 " // apply light cubemap filter\n"
410 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
413 " // calculate fragment color\n"
414 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
418 void r_shadow_start(void)
421 // allocate vertex processing arrays
423 r_shadow_attenuation2dtexture = NULL;
424 r_shadow_attenuation3dtexture = NULL;
425 r_shadow_texturepool = NULL;
426 r_shadow_filters_texturepool = NULL;
427 R_Shadow_ValidateCvars();
428 R_Shadow_MakeTextures();
429 maxshadowelements = 0;
430 shadowelements = NULL;
438 shadowmarklist = NULL;
440 r_shadow_buffer_numleafpvsbytes = 0;
441 r_shadow_buffer_leafpvs = NULL;
442 r_shadow_buffer_leaflist = NULL;
443 r_shadow_buffer_numsurfacepvsbytes = 0;
444 r_shadow_buffer_surfacepvs = NULL;
445 r_shadow_buffer_surfacelist = NULL;
446 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
447 r_shadow_program_light[i] = 0;
448 if (gl_support_fragment_shader)
450 char *vertstring, *fragstring;
451 int vertstrings_count;
452 int fragstrings_count;
453 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
454 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
455 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
456 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
457 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
459 vertstrings_count = 0;
460 fragstrings_count = 0;
461 if (i & SHADERPERMUTATION_SPECULAR)
463 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
464 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
466 if (i & SHADERPERMUTATION_FOG)
468 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
469 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
471 if (i & SHADERPERMUTATION_CUBEFILTER)
473 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
474 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
476 if (i & SHADERPERMUTATION_OFFSETMAPPING)
478 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
479 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
481 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
482 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
483 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
484 if (!r_shadow_program_light[i])
486 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");
489 qglUseProgramObjectARB(r_shadow_program_light[i]);
490 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
491 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
492 if (i & SHADERPERMUTATION_SPECULAR)
494 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
496 if (i & SHADERPERMUTATION_CUBEFILTER)
498 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
500 if (i & SHADERPERMUTATION_FOG)
502 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
505 qglUseProgramObjectARB(0);
507 Mem_Free(fragstring);
509 Mem_Free(vertstring);
513 void r_shadow_shutdown(void)
516 R_Shadow_UncompileWorldLights();
517 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
519 if (r_shadow_program_light[i])
521 GL_Backend_FreeProgram(r_shadow_program_light[i]);
522 r_shadow_program_light[i] = 0;
526 r_shadow_attenuation2dtexture = NULL;
527 r_shadow_attenuation3dtexture = NULL;
528 R_FreeTexturePool(&r_shadow_texturepool);
529 R_FreeTexturePool(&r_shadow_filters_texturepool);
530 maxshadowelements = 0;
532 Mem_Free(shadowelements);
533 shadowelements = NULL;
536 Mem_Free(vertexupdate);
539 Mem_Free(vertexremap);
545 Mem_Free(shadowmark);
548 Mem_Free(shadowmarklist);
549 shadowmarklist = NULL;
551 r_shadow_buffer_numleafpvsbytes = 0;
552 if (r_shadow_buffer_leafpvs)
553 Mem_Free(r_shadow_buffer_leafpvs);
554 r_shadow_buffer_leafpvs = NULL;
555 if (r_shadow_buffer_leaflist)
556 Mem_Free(r_shadow_buffer_leaflist);
557 r_shadow_buffer_leaflist = NULL;
558 r_shadow_buffer_numsurfacepvsbytes = 0;
559 if (r_shadow_buffer_surfacepvs)
560 Mem_Free(r_shadow_buffer_surfacepvs);
561 r_shadow_buffer_surfacepvs = NULL;
562 if (r_shadow_buffer_surfacelist)
563 Mem_Free(r_shadow_buffer_surfacelist);
564 r_shadow_buffer_surfacelist = NULL;
567 void r_shadow_newmap(void)
571 void R_Shadow_Help_f(void)
574 "Documentation on r_shadow system:\n"
576 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
577 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
578 "r_shadow_debuglight : render only this light number (-1 = all)\n"
579 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
580 "r_shadow_gloss2intensity : brightness of forced gloss\n"
581 "r_shadow_glossintensity : brightness of textured gloss\n"
582 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
583 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
584 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
585 "r_shadow_portallight : use portal visibility for static light precomputation\n"
586 "r_shadow_projectdistance : shadow volume projection distance\n"
587 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
588 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
589 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
590 "r_shadow_realtime_world : use high quality world lighting mode\n"
591 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
592 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
593 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
594 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
595 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
596 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
597 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
598 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
599 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
600 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
601 "r_shadow_scissor : use scissor optimization\n"
602 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
603 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
604 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
605 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
606 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
607 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
609 "r_shadow_help : this help\n"
613 void R_Shadow_Init(void)
615 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
616 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
617 Cvar_RegisterVariable(&r_shadow_debuglight);
618 Cvar_RegisterVariable(&r_shadow_gloss);
619 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
620 Cvar_RegisterVariable(&r_shadow_glossintensity);
621 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
622 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
623 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
624 Cvar_RegisterVariable(&r_shadow_portallight);
625 Cvar_RegisterVariable(&r_shadow_projectdistance);
626 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
627 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
628 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
629 Cvar_RegisterVariable(&r_shadow_realtime_world);
630 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
631 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
632 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
633 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
634 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
635 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
636 Cvar_RegisterVariable(&r_shadow_scissor);
637 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
638 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
639 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
640 Cvar_RegisterVariable(&r_shadow_texture3d);
641 Cvar_RegisterVariable(&r_shadow_visiblelighting);
642 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
643 Cvar_RegisterVariable(&r_shadow_glsl);
644 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
645 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
646 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
647 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
648 if (gamemode == GAME_TENEBRAE)
650 Cvar_SetValue("r_shadow_gloss", 2);
651 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
653 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
654 R_Shadow_EditLights_Init();
655 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
656 r_shadow_worldlightchain = NULL;
657 maxshadowelements = 0;
658 shadowelements = NULL;
666 shadowmarklist = NULL;
668 r_shadow_buffer_numleafpvsbytes = 0;
669 r_shadow_buffer_leafpvs = NULL;
670 r_shadow_buffer_leaflist = NULL;
671 r_shadow_buffer_numsurfacepvsbytes = 0;
672 r_shadow_buffer_surfacepvs = NULL;
673 r_shadow_buffer_surfacelist = NULL;
674 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
677 static matrix4x4_t matrix_attenuationxyz =
680 {0.5, 0.0, 0.0, 0.5},
681 {0.0, 0.5, 0.0, 0.5},
682 {0.0, 0.0, 0.5, 0.5},
687 static matrix4x4_t matrix_attenuationz =
690 {0.0, 0.0, 0.5, 0.5},
691 {0.0, 0.0, 0.0, 0.5},
692 {0.0, 0.0, 0.0, 0.5},
697 int *R_Shadow_ResizeShadowElements(int numtris)
699 // make sure shadowelements is big enough for this volume
700 if (maxshadowelements < numtris * 24)
702 maxshadowelements = numtris * 24;
704 Mem_Free(shadowelements);
705 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
707 return shadowelements;
710 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
712 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
713 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
714 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
716 if (r_shadow_buffer_leafpvs)
717 Mem_Free(r_shadow_buffer_leafpvs);
718 if (r_shadow_buffer_leaflist)
719 Mem_Free(r_shadow_buffer_leaflist);
720 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
721 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
722 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
724 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
726 if (r_shadow_buffer_surfacepvs)
727 Mem_Free(r_shadow_buffer_surfacepvs);
728 if (r_shadow_buffer_surfacelist)
729 Mem_Free(r_shadow_buffer_surfacelist);
730 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
731 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
732 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
736 void R_Shadow_PrepareShadowMark(int numtris)
738 // make sure shadowmark is big enough for this volume
739 if (maxshadowmark < numtris)
741 maxshadowmark = numtris;
743 Mem_Free(shadowmark);
745 Mem_Free(shadowmarklist);
746 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
747 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
751 // if shadowmarkcount wrapped we clear the array and adjust accordingly
752 if (shadowmarkcount == 0)
755 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
760 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)
763 int outtriangles = 0, outvertices = 0;
767 if (maxvertexupdate < innumvertices)
769 maxvertexupdate = innumvertices;
771 Mem_Free(vertexupdate);
773 Mem_Free(vertexremap);
774 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
775 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
779 if (vertexupdatenum == 0)
782 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
783 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
786 for (i = 0;i < numshadowmarktris;i++)
787 shadowmark[shadowmarktris[i]] = shadowmarkcount;
789 for (i = 0;i < numshadowmarktris;i++)
791 element = inelement3i + shadowmarktris[i] * 3;
792 // make sure the vertices are created
793 for (j = 0;j < 3;j++)
795 if (vertexupdate[element[j]] != vertexupdatenum)
797 float ratio, direction[3];
798 vertexupdate[element[j]] = vertexupdatenum;
799 vertexremap[element[j]] = outvertices;
800 vertex = invertex3f + element[j] * 3;
801 // project one copy of the vertex to the sphere radius of the light
802 // (FIXME: would projecting it to the light box be better?)
803 VectorSubtract(vertex, projectorigin, direction);
804 ratio = projectdistance / VectorLength(direction);
805 VectorCopy(vertex, outvertex3f);
806 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
813 for (i = 0;i < numshadowmarktris;i++)
815 int remappedelement[3];
817 const int *neighbortriangle;
819 markindex = shadowmarktris[i] * 3;
820 element = inelement3i + markindex;
821 neighbortriangle = inneighbor3i + markindex;
822 // output the front and back triangles
823 outelement3i[0] = vertexremap[element[0]];
824 outelement3i[1] = vertexremap[element[1]];
825 outelement3i[2] = vertexremap[element[2]];
826 outelement3i[3] = vertexremap[element[2]] + 1;
827 outelement3i[4] = vertexremap[element[1]] + 1;
828 outelement3i[5] = vertexremap[element[0]] + 1;
832 // output the sides (facing outward from this triangle)
833 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
835 remappedelement[0] = vertexremap[element[0]];
836 remappedelement[1] = vertexremap[element[1]];
837 outelement3i[0] = remappedelement[1];
838 outelement3i[1] = remappedelement[0];
839 outelement3i[2] = remappedelement[0] + 1;
840 outelement3i[3] = remappedelement[1];
841 outelement3i[4] = remappedelement[0] + 1;
842 outelement3i[5] = remappedelement[1] + 1;
847 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
849 remappedelement[1] = vertexremap[element[1]];
850 remappedelement[2] = vertexremap[element[2]];
851 outelement3i[0] = remappedelement[2];
852 outelement3i[1] = remappedelement[1];
853 outelement3i[2] = remappedelement[1] + 1;
854 outelement3i[3] = remappedelement[2];
855 outelement3i[4] = remappedelement[1] + 1;
856 outelement3i[5] = remappedelement[2] + 1;
861 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
863 remappedelement[0] = vertexremap[element[0]];
864 remappedelement[2] = vertexremap[element[2]];
865 outelement3i[0] = remappedelement[0];
866 outelement3i[1] = remappedelement[2];
867 outelement3i[2] = remappedelement[2] + 1;
868 outelement3i[3] = remappedelement[0];
869 outelement3i[4] = remappedelement[2] + 1;
870 outelement3i[5] = remappedelement[0] + 1;
877 *outnumvertices = outvertices;
881 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)
884 if (projectdistance < 0.1)
886 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
889 if (!numverts || !nummarktris)
891 // make sure shadowelements is big enough for this volume
892 if (maxshadowelements < nummarktris * 24)
893 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
894 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
895 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
898 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)
903 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
905 tend = firsttriangle + numtris;
906 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
907 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
908 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
910 // surface box entirely inside light box, no box cull
911 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
912 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
913 shadowmarklist[numshadowmark++] = t;
917 // surface box not entirely inside light box, cull each triangle
918 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
920 v[0] = invertex3f + e[0] * 3;
921 v[1] = invertex3f + e[1] * 3;
922 v[2] = invertex3f + e[2] * 3;
923 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
924 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
925 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
926 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
927 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
928 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
929 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
930 shadowmarklist[numshadowmark++] = t;
935 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
938 if (r_shadow_compilingrtlight)
940 // if we're compiling an rtlight, capture the mesh
941 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
944 memset(&m, 0, sizeof(m));
945 m.pointer_vertex = vertex3f;
947 GL_LockArrays(0, numvertices);
948 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
950 // increment stencil if backface is behind depthbuffer
951 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
952 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
953 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
955 c_rt_shadowtris += numtriangles;
956 // decrement stencil if frontface is behind depthbuffer
957 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
958 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
960 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
962 c_rt_shadowtris += numtriangles;
966 static void R_Shadow_MakeTextures(void)
969 float v[3], intensity;
971 R_FreeTexturePool(&r_shadow_texturepool);
972 r_shadow_texturepool = R_AllocTexturePool();
973 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
974 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
975 #define ATTEN2DSIZE 64
976 #define ATTEN3DSIZE 32
977 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
978 for (y = 0;y < ATTEN2DSIZE;y++)
980 for (x = 0;x < ATTEN2DSIZE;x++)
982 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
983 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
985 intensity = 1.0f - sqrt(DotProduct(v, v));
987 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
988 d = bound(0, intensity, 255);
989 data[(y*ATTEN2DSIZE+x)*4+0] = d;
990 data[(y*ATTEN2DSIZE+x)*4+1] = d;
991 data[(y*ATTEN2DSIZE+x)*4+2] = d;
992 data[(y*ATTEN2DSIZE+x)*4+3] = d;
995 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
996 if (r_shadow_texture3d.integer)
998 for (z = 0;z < ATTEN3DSIZE;z++)
1000 for (y = 0;y < ATTEN3DSIZE;y++)
1002 for (x = 0;x < ATTEN3DSIZE;x++)
1004 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1005 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1006 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1007 intensity = 1.0f - sqrt(DotProduct(v, v));
1009 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1010 d = bound(0, intensity, 255);
1011 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1012 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1013 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1014 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1018 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1023 void R_Shadow_ValidateCvars(void)
1025 if (r_shadow_texture3d.integer && !gl_texture3d)
1026 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1027 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1028 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1031 // light currently being rendered
1032 static rtlight_t *r_shadow_rtlight;
1033 // light filter cubemap being used by the light
1034 static rtexture_t *r_shadow_lightcubemap;
1036 // this is the location of the eye in entity space
1037 static vec3_t r_shadow_entityeyeorigin;
1038 // this is the location of the light in entity space
1039 static vec3_t r_shadow_entitylightorigin;
1040 // this transforms entity coordinates to light filter cubemap coordinates
1041 // (also often used for other purposes)
1042 static matrix4x4_t r_shadow_entitytolight;
1043 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1044 // of attenuation texturing in full 3D (Z result often ignored)
1045 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1046 // this transforms only the Z to S, and T is always 0.5
1047 static matrix4x4_t r_shadow_entitytoattenuationz;
1048 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1049 static vec3_t r_shadow_entitylightcolor;
1051 static int r_shadow_lightpermutation;
1052 static int r_shadow_lightprog;
1054 void R_Shadow_Stage_Begin(void)
1058 R_Shadow_ValidateCvars();
1060 if (!r_shadow_attenuation2dtexture
1061 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1062 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1063 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1064 R_Shadow_MakeTextures();
1066 memset(&m, 0, sizeof(m));
1067 GL_BlendFunc(GL_ONE, GL_ZERO);
1068 GL_DepthMask(false);
1071 GL_Color(0, 0, 0, 1);
1072 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1073 qglEnable(GL_CULL_FACE);
1074 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1075 r_shadowstage = R_SHADOWSTAGE_NONE;
1078 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1080 r_shadow_rtlight = rtlight;
1083 void R_Shadow_Stage_Reset(void)
1086 if (gl_support_stenciltwoside)
1087 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1088 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1090 qglUseProgramObjectARB(0);
1091 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1092 qglBegin(GL_TRIANGLES);
1096 memset(&m, 0, sizeof(m));
1100 void R_Shadow_Stage_StencilShadowVolumes(void)
1102 R_Shadow_Stage_Reset();
1103 GL_Color(1, 1, 1, 1);
1104 GL_ColorMask(0, 0, 0, 0);
1105 GL_BlendFunc(GL_ONE, GL_ZERO);
1106 GL_DepthMask(false);
1108 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1109 //if (r_shadow_shadow_polygonoffset.value != 0)
1111 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1112 // qglEnable(GL_POLYGON_OFFSET_FILL);
1115 // qglDisable(GL_POLYGON_OFFSET_FILL);
1116 qglDepthFunc(GL_GEQUAL);
1117 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1118 qglEnable(GL_STENCIL_TEST);
1119 qglStencilFunc(GL_ALWAYS, 128, ~0);
1120 if (gl_ext_stenciltwoside.integer)
1122 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1123 qglDisable(GL_CULL_FACE);
1124 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1125 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1127 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
1128 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1130 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1134 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1135 qglEnable(GL_CULL_FACE);
1137 // this is changed by every shadow render so its value here is unimportant
1138 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1140 GL_Clear(GL_STENCIL_BUFFER_BIT);
1144 void R_Shadow_Stage_Lighting(int stenciltest)
1147 R_Shadow_Stage_Reset();
1148 GL_BlendFunc(GL_ONE, GL_ONE);
1149 GL_DepthMask(false);
1151 qglPolygonOffset(0, 0);
1152 //qglDisable(GL_POLYGON_OFFSET_FILL);
1153 GL_Color(1, 1, 1, 1);
1154 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1155 qglDepthFunc(GL_EQUAL);
1156 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1157 qglEnable(GL_CULL_FACE);
1158 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1159 qglEnable(GL_STENCIL_TEST);
1161 qglDisable(GL_STENCIL_TEST);
1163 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1164 // only draw light where this geometry was already rendered AND the
1165 // stencil is 128 (values other than this mean shadow)
1166 qglStencilFunc(GL_EQUAL, 128, ~0);
1167 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1169 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1170 memset(&m, 0, sizeof(m));
1171 m.pointer_vertex = varray_vertex3f;
1172 m.pointer_texcoord[0] = varray_texcoord2f[0];
1173 m.pointer_texcoord3f[1] = varray_svector3f;
1174 m.pointer_texcoord3f[2] = varray_tvector3f;
1175 m.pointer_texcoord3f[3] = varray_normal3f;
1176 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1177 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1178 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1179 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1180 // TODO: support fog (after renderer is converted to texture fog)
1181 m.tex[4] = R_GetTexture(r_texture_white); // fog
1182 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1184 GL_BlendFunc(GL_ONE, GL_ONE);
1185 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1187 r_shadow_lightpermutation = 0;
1188 // only add a feature to the permutation if that permutation exists
1189 // (otherwise it might end up not using a shader at all, which looks
1190 // worse than using less features)
1191 if (r_shadow_rtlight->specularscale && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1192 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1193 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1194 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1195 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1196 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1197 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1198 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1199 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1200 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1201 // TODO: support fog (after renderer is converted to texture fog)
1202 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1204 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1206 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1207 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1208 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1210 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1211 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1213 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1214 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1215 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1217 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1219 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1221 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1222 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1225 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1226 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1228 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1231 void R_Shadow_Stage_VisibleShadowVolumes(void)
1233 R_Shadow_Stage_Reset();
1234 GL_BlendFunc(GL_ONE, GL_ONE);
1235 GL_DepthMask(false);
1236 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1237 qglPolygonOffset(0, 0);
1238 GL_Color(0.0, 0.0125, 0.1, 1);
1239 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1240 qglDepthFunc(GL_GEQUAL);
1241 qglCullFace(GL_FRONT); // this culls back
1242 qglDisable(GL_CULL_FACE);
1243 qglDisable(GL_STENCIL_TEST);
1244 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1247 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1249 R_Shadow_Stage_Reset();
1250 GL_BlendFunc(GL_ONE, GL_ONE);
1251 GL_DepthMask(false);
1252 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1253 qglPolygonOffset(0, 0);
1254 GL_Color(0.1, 0.0125, 0, 1);
1255 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1256 qglDepthFunc(GL_EQUAL);
1257 qglCullFace(GL_FRONT); // this culls back
1258 qglEnable(GL_CULL_FACE);
1260 qglEnable(GL_STENCIL_TEST);
1262 qglDisable(GL_STENCIL_TEST);
1263 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1266 void R_Shadow_Stage_End(void)
1268 R_Shadow_Stage_Reset();
1269 R_Shadow_Stage_ActiveLight(NULL);
1270 GL_BlendFunc(GL_ONE, GL_ZERO);
1273 qglPolygonOffset(0, 0);
1274 //qglDisable(GL_POLYGON_OFFSET_FILL);
1275 GL_Color(1, 1, 1, 1);
1276 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1277 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1278 qglDepthFunc(GL_LEQUAL);
1279 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1280 qglDisable(GL_STENCIL_TEST);
1281 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1282 if (gl_support_stenciltwoside)
1283 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1285 qglStencilFunc(GL_ALWAYS, 128, ~0);
1286 r_shadowstage = R_SHADOWSTAGE_NONE;
1289 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1291 int i, ix1, iy1, ix2, iy2;
1292 float x1, y1, x2, y2;
1295 mplane_t planes[11];
1296 float vertex3f[256*3];
1298 // if view is inside the light box, just say yes it's visible
1299 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1301 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1305 // create a temporary brush describing the area the light can affect in worldspace
1306 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1307 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1308 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1309 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1310 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1311 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1312 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1313 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1314 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1315 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1316 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1318 // turn the brush into a mesh
1319 memset(&mesh, 0, sizeof(rmesh_t));
1320 mesh.maxvertices = 256;
1321 mesh.vertex3f = vertex3f;
1322 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1323 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1325 // if that mesh is empty, the light is not visible at all
1326 if (!mesh.numvertices)
1329 if (!r_shadow_scissor.integer)
1332 // if that mesh is not empty, check what area of the screen it covers
1333 x1 = y1 = x2 = y2 = 0;
1335 for (i = 0;i < mesh.numvertices;i++)
1337 VectorCopy(mesh.vertex3f + i * 3, v);
1338 GL_TransformToScreen(v, v2);
1339 //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]);
1342 if (x1 > v2[0]) x1 = v2[0];
1343 if (x2 < v2[0]) x2 = v2[0];
1344 if (y1 > v2[1]) y1 = v2[1];
1345 if (y2 < v2[1]) y2 = v2[1];
1354 // now convert the scissor rectangle to integer screen coordinates
1359 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1361 // clamp it to the screen
1362 if (ix1 < r_view_x) ix1 = r_view_x;
1363 if (iy1 < r_view_y) iy1 = r_view_y;
1364 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1365 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1367 // if it is inside out, it's not visible
1368 if (ix2 <= ix1 || iy2 <= iy1)
1371 // the light area is visible, set up the scissor rectangle
1372 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1373 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1374 //qglEnable(GL_SCISSOR_TEST);
1379 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1381 float *color4f = varray_color4f;
1382 float dist, dot, intensity, v[3], n[3];
1383 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1385 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1386 if ((dist = DotProduct(v, v)) < 1)
1388 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1389 if ((dot = DotProduct(n, v)) > 0)
1392 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1393 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1394 VectorScale(lightcolor, intensity, color4f);
1399 VectorClear(color4f);
1405 VectorClear(color4f);
1411 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1413 float *color4f = varray_color4f;
1414 float dist, dot, intensity, v[3], n[3];
1415 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1417 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1418 if ((dist = fabs(v[2])) < 1)
1420 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1421 if ((dot = DotProduct(n, v)) > 0)
1423 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1424 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1425 VectorScale(lightcolor, intensity, color4f);
1430 VectorClear(color4f);
1436 VectorClear(color4f);
1442 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1444 float *color4f = varray_color4f;
1445 float dot, intensity, v[3], n[3];
1446 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1448 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1449 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1450 if ((dot = DotProduct(n, v)) > 0)
1452 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1453 VectorScale(lightcolor, intensity, color4f);
1458 VectorClear(color4f);
1464 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1466 float *color4f = varray_color4f;
1467 float dist, intensity, v[3];
1468 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1470 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1471 if ((dist = DotProduct(v, v)) < 1)
1474 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1475 VectorScale(lightcolor, intensity, color4f);
1480 VectorClear(color4f);
1486 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1488 float *color4f = varray_color4f;
1489 float dist, intensity, v[3];
1490 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1492 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1493 if ((dist = fabs(v[2])) < 1)
1495 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1496 VectorScale(lightcolor, intensity, color4f);
1501 VectorClear(color4f);
1507 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1508 #define USETEXMATRIX
1510 #ifndef USETEXMATRIX
1511 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1512 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1513 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1517 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1518 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1519 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1526 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1530 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1531 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1539 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)
1543 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1545 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1546 // the cubemap normalizes this for us
1547 out3f[0] = DotProduct(svector3f, lightdir);
1548 out3f[1] = DotProduct(tvector3f, lightdir);
1549 out3f[2] = DotProduct(normal3f, lightdir);
1553 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)
1556 float lightdir[3], eyedir[3], halfdir[3];
1557 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1559 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1560 VectorNormalizeFast(lightdir);
1561 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1562 VectorNormalizeFast(eyedir);
1563 VectorAdd(lightdir, eyedir, halfdir);
1564 // the cubemap normalizes this for us
1565 out3f[0] = DotProduct(svector3f, halfdir);
1566 out3f[1] = DotProduct(tvector3f, halfdir);
1567 out3f[2] = DotProduct(normal3f, halfdir);
1571 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)
1574 float color[3], color2[3], colorscale, specularscale;
1576 // FIXME: support EF_NODEPTHTEST
1578 basetexture = r_texture_white;
1580 bumptexture = r_texture_blanknormalmap;
1582 lightcolorpants = vec3_origin;
1584 lightcolorshirt = vec3_origin;
1585 if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1586 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
1587 else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1589 glosstexture = r_texture_white;
1590 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
1594 glosstexture = r_texture_black;
1597 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1599 if (r_shadowstage == R_SHADOWSTAGE_VISIBLELIGHTING)
1602 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1603 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1604 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1606 // TODO: add direct pants/shirt rendering
1607 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1608 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1609 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1610 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1611 if (r_shadow_rtlight->ambientscale)
1613 colorscale = r_shadow_rtlight->ambientscale;
1614 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1617 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1620 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1623 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1628 VectorScale(lightcolorbase, colorscale, color2);
1629 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1632 if (r_shadow_rtlight->diffusescale)
1634 colorscale = r_shadow_rtlight->diffusescale;
1635 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1637 // 3/2 3D combine path (Geforce3, Radeon 8500)
1640 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1642 // 1/2/2 3D combine path (original Radeon)
1645 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1647 // 2/2 3D combine path (original Radeon)
1650 else if (r_textureunits.integer >= 4)
1652 // 4/2 2D combine path (Geforce3, Radeon 8500)
1657 // 2/2/2 2D combine path (any dot3 card)
1660 VectorScale(lightcolorbase, colorscale, color2);
1661 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1664 if (specularscale && glosstexture != r_texture_black)
1666 //if (gl_support_blendsquare)
1668 colorscale = specularscale;
1669 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1671 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1675 VectorScale(lightcolorbase, colorscale, color2);
1676 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1683 // TODO: add direct pants/shirt rendering
1684 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1685 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1686 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1687 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1688 if (r_shadow_rtlight->ambientscale)
1690 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
1691 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1694 if (r_shadow_rtlight->diffusescale)
1696 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
1697 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1703 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1704 memset(&m, 0, sizeof(m));
1705 m.pointer_vertex = vertex3f;
1707 GL_LockArrays(firstvertex, numvertices);
1708 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1709 GL_LockArrays(0, 0);
1713 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1715 // GLSL shader path (GFFX5200, Radeon 9500)
1716 R_Mesh_VertexPointer(vertex3f);
1717 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1718 R_Mesh_TexCoordPointer(1, 3, svector3f);
1719 R_Mesh_TexCoordPointer(2, 3, tvector3f);
1720 R_Mesh_TexCoordPointer(3, 3, normal3f);
1721 R_Mesh_TexBind(0, R_GetTexture(bumptexture));
1722 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1723 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1724 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1726 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1728 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1729 GL_LockArrays(firstvertex, numvertices);
1730 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1732 c_rt_lighttris += numtriangles;
1733 // TODO: add direct pants/shirt rendering
1734 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1736 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1737 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1738 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1740 c_rt_lighttris += numtriangles;
1742 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1744 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1745 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1746 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1748 c_rt_lighttris += numtriangles;
1750 GL_LockArrays(0, 0);
1752 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
1754 // TODO: add direct pants/shirt rendering
1755 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1756 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1757 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1758 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1759 if (r_shadow_rtlight->ambientscale)
1762 colorscale = r_shadow_rtlight->ambientscale;
1763 // colorscale accounts for how much we multiply the brightness
1766 // mult is how many times the final pass of the lighting will be
1767 // performed to get more brightness than otherwise possible.
1769 // Limit mult to 64 for sanity sake.
1770 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1772 // 3 3D combine path (Geforce3, Radeon 8500)
1773 memset(&m, 0, sizeof(m));
1774 m.pointer_vertex = vertex3f;
1775 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1777 m.pointer_texcoord3f[0] = vertex3f;
1778 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1780 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1781 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1783 m.tex[1] = R_GetTexture(basetexture);
1784 m.pointer_texcoord[1] = texcoord2f;
1785 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1787 m.pointer_texcoord3f[2] = vertex3f;
1788 m.texmatrix[2] = r_shadow_entitytolight;
1790 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1791 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1793 GL_BlendFunc(GL_ONE, GL_ONE);
1795 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1797 // 2 3D combine path (Geforce3, original Radeon)
1798 memset(&m, 0, sizeof(m));
1799 m.pointer_vertex = vertex3f;
1800 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1802 m.pointer_texcoord3f[0] = vertex3f;
1803 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1805 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1806 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1808 m.tex[1] = R_GetTexture(basetexture);
1809 m.pointer_texcoord[1] = texcoord2f;
1810 GL_BlendFunc(GL_ONE, GL_ONE);
1812 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1814 // 4 2D combine path (Geforce3, Radeon 8500)
1815 memset(&m, 0, sizeof(m));
1816 m.pointer_vertex = vertex3f;
1817 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1819 m.pointer_texcoord3f[0] = vertex3f;
1820 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1822 m.pointer_texcoord[0] = varray_texcoord2f[0];
1823 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1825 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1827 m.pointer_texcoord3f[1] = vertex3f;
1828 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1830 m.pointer_texcoord[1] = varray_texcoord2f[1];
1831 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1833 m.tex[2] = R_GetTexture(basetexture);
1834 m.pointer_texcoord[2] = texcoord2f;
1835 if (r_shadow_lightcubemap != r_texture_whitecube)
1837 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1839 m.pointer_texcoord3f[3] = vertex3f;
1840 m.texmatrix[3] = r_shadow_entitytolight;
1842 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1843 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1846 GL_BlendFunc(GL_ONE, GL_ONE);
1848 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1850 // 3 2D combine path (Geforce3, original Radeon)
1851 memset(&m, 0, sizeof(m));
1852 m.pointer_vertex = vertex3f;
1853 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1855 m.pointer_texcoord3f[0] = vertex3f;
1856 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1858 m.pointer_texcoord[0] = varray_texcoord2f[0];
1859 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1861 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1863 m.pointer_texcoord3f[1] = vertex3f;
1864 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1866 m.pointer_texcoord[1] = varray_texcoord2f[1];
1867 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1869 m.tex[2] = R_GetTexture(basetexture);
1870 m.pointer_texcoord[2] = texcoord2f;
1871 GL_BlendFunc(GL_ONE, GL_ONE);
1875 // 2/2/2 2D combine path (any dot3 card)
1876 memset(&m, 0, sizeof(m));
1877 m.pointer_vertex = vertex3f;
1878 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1880 m.pointer_texcoord3f[0] = vertex3f;
1881 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1883 m.pointer_texcoord[0] = varray_texcoord2f[0];
1884 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1886 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1888 m.pointer_texcoord3f[1] = vertex3f;
1889 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1891 m.pointer_texcoord[1] = varray_texcoord2f[1];
1892 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1895 GL_ColorMask(0,0,0,1);
1896 GL_BlendFunc(GL_ONE, GL_ZERO);
1897 GL_LockArrays(firstvertex, numvertices);
1898 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1899 GL_LockArrays(0, 0);
1901 c_rt_lighttris += numtriangles;
1903 memset(&m, 0, sizeof(m));
1904 m.pointer_vertex = vertex3f;
1905 m.tex[0] = R_GetTexture(basetexture);
1906 m.pointer_texcoord[0] = texcoord2f;
1907 if (r_shadow_lightcubemap != r_texture_whitecube)
1909 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1911 m.pointer_texcoord3f[1] = vertex3f;
1912 m.texmatrix[1] = r_shadow_entitytolight;
1914 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1915 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1918 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1920 // this final code is shared
1922 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1923 VectorScale(lightcolorbase, colorscale, color2);
1924 GL_LockArrays(firstvertex, numvertices);
1925 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1927 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1928 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1930 c_rt_lighttris += numtriangles;
1932 GL_LockArrays(0, 0);
1934 if (r_shadow_rtlight->diffusescale)
1937 colorscale = r_shadow_rtlight->diffusescale;
1938 // colorscale accounts for how much we multiply the brightness
1941 // mult is how many times the final pass of the lighting will be
1942 // performed to get more brightness than otherwise possible.
1944 // Limit mult to 64 for sanity sake.
1945 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1947 // 3/2 3D combine path (Geforce3, Radeon 8500)
1948 memset(&m, 0, sizeof(m));
1949 m.pointer_vertex = vertex3f;
1950 m.tex[0] = R_GetTexture(bumptexture);
1951 m.texcombinergb[0] = GL_REPLACE;
1952 m.pointer_texcoord[0] = texcoord2f;
1953 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1954 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1955 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1956 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);
1957 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1959 m.pointer_texcoord3f[2] = vertex3f;
1960 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1962 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1963 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1966 GL_ColorMask(0,0,0,1);
1967 GL_BlendFunc(GL_ONE, GL_ZERO);
1968 GL_LockArrays(firstvertex, numvertices);
1969 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1970 GL_LockArrays(0, 0);
1972 c_rt_lighttris += numtriangles;
1974 memset(&m, 0, sizeof(m));
1975 m.pointer_vertex = vertex3f;
1976 m.tex[0] = R_GetTexture(basetexture);
1977 m.pointer_texcoord[0] = texcoord2f;
1978 if (r_shadow_lightcubemap != r_texture_whitecube)
1980 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1982 m.pointer_texcoord3f[1] = vertex3f;
1983 m.texmatrix[1] = r_shadow_entitytolight;
1985 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1986 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1989 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1991 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1993 // 1/2/2 3D combine path (original Radeon)
1994 memset(&m, 0, sizeof(m));
1995 m.pointer_vertex = vertex3f;
1996 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1998 m.pointer_texcoord3f[0] = vertex3f;
1999 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2001 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2002 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2005 GL_ColorMask(0,0,0,1);
2006 GL_BlendFunc(GL_ONE, GL_ZERO);
2007 GL_LockArrays(firstvertex, numvertices);
2008 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2009 GL_LockArrays(0, 0);
2011 c_rt_lighttris += numtriangles;
2013 memset(&m, 0, sizeof(m));
2014 m.pointer_vertex = vertex3f;
2015 m.tex[0] = R_GetTexture(bumptexture);
2016 m.texcombinergb[0] = GL_REPLACE;
2017 m.pointer_texcoord[0] = texcoord2f;
2018 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2019 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2020 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2021 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);
2023 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2024 GL_LockArrays(firstvertex, numvertices);
2025 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2026 GL_LockArrays(0, 0);
2028 c_rt_lighttris += numtriangles;
2030 memset(&m, 0, sizeof(m));
2031 m.pointer_vertex = vertex3f;
2032 m.tex[0] = R_GetTexture(basetexture);
2033 m.pointer_texcoord[0] = texcoord2f;
2034 if (r_shadow_lightcubemap != r_texture_whitecube)
2036 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2038 m.pointer_texcoord3f[1] = vertex3f;
2039 m.texmatrix[1] = r_shadow_entitytolight;
2041 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2042 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2045 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2047 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2049 // 2/2 3D combine path (original Radeon)
2050 memset(&m, 0, sizeof(m));
2051 m.pointer_vertex = vertex3f;
2052 m.tex[0] = R_GetTexture(bumptexture);
2053 m.texcombinergb[0] = GL_REPLACE;
2054 m.pointer_texcoord[0] = texcoord2f;
2055 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2056 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2057 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2058 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);
2060 GL_ColorMask(0,0,0,1);
2061 GL_BlendFunc(GL_ONE, GL_ZERO);
2062 GL_LockArrays(firstvertex, numvertices);
2063 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2064 GL_LockArrays(0, 0);
2066 c_rt_lighttris += numtriangles;
2068 memset(&m, 0, sizeof(m));
2069 m.pointer_vertex = vertex3f;
2070 m.tex[0] = R_GetTexture(basetexture);
2071 m.pointer_texcoord[0] = texcoord2f;
2072 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2074 m.pointer_texcoord3f[1] = vertex3f;
2075 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2077 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2078 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2080 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2082 else if (r_textureunits.integer >= 4)
2084 // 4/2 2D combine path (Geforce3, Radeon 8500)
2085 memset(&m, 0, sizeof(m));
2086 m.pointer_vertex = vertex3f;
2087 m.tex[0] = R_GetTexture(bumptexture);
2088 m.texcombinergb[0] = GL_REPLACE;
2089 m.pointer_texcoord[0] = texcoord2f;
2090 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2091 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2092 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2093 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);
2094 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2096 m.pointer_texcoord3f[2] = vertex3f;
2097 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2099 m.pointer_texcoord[2] = varray_texcoord2f[2];
2100 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2102 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2104 m.pointer_texcoord3f[3] = vertex3f;
2105 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2107 m.pointer_texcoord[3] = varray_texcoord2f[3];
2108 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2111 GL_ColorMask(0,0,0,1);
2112 GL_BlendFunc(GL_ONE, GL_ZERO);
2113 GL_LockArrays(firstvertex, numvertices);
2114 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2115 GL_LockArrays(0, 0);
2117 c_rt_lighttris += numtriangles;
2119 memset(&m, 0, sizeof(m));
2120 m.pointer_vertex = vertex3f;
2121 m.tex[0] = R_GetTexture(basetexture);
2122 m.pointer_texcoord[0] = texcoord2f;
2123 if (r_shadow_lightcubemap != r_texture_whitecube)
2125 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2127 m.pointer_texcoord3f[1] = vertex3f;
2128 m.texmatrix[1] = r_shadow_entitytolight;
2130 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2131 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2134 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2138 // 2/2/2 2D combine path (any dot3 card)
2139 memset(&m, 0, sizeof(m));
2140 m.pointer_vertex = vertex3f;
2141 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2143 m.pointer_texcoord3f[0] = vertex3f;
2144 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2146 m.pointer_texcoord[0] = varray_texcoord2f[0];
2147 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2149 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2151 m.pointer_texcoord3f[1] = vertex3f;
2152 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2154 m.pointer_texcoord[1] = varray_texcoord2f[1];
2155 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2158 GL_ColorMask(0,0,0,1);
2159 GL_BlendFunc(GL_ONE, GL_ZERO);
2160 GL_LockArrays(firstvertex, numvertices);
2161 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2162 GL_LockArrays(0, 0);
2164 c_rt_lighttris += numtriangles;
2166 memset(&m, 0, sizeof(m));
2167 m.pointer_vertex = vertex3f;
2168 m.tex[0] = R_GetTexture(bumptexture);
2169 m.texcombinergb[0] = GL_REPLACE;
2170 m.pointer_texcoord[0] = texcoord2f;
2171 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2172 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2173 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2174 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);
2176 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2177 GL_LockArrays(firstvertex, numvertices);
2178 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2179 GL_LockArrays(0, 0);
2181 c_rt_lighttris += numtriangles;
2183 memset(&m, 0, sizeof(m));
2184 m.pointer_vertex = vertex3f;
2185 m.tex[0] = R_GetTexture(basetexture);
2186 m.pointer_texcoord[0] = texcoord2f;
2187 if (r_shadow_lightcubemap != r_texture_whitecube)
2189 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2191 m.pointer_texcoord3f[1] = vertex3f;
2192 m.texmatrix[1] = r_shadow_entitytolight;
2194 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2195 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2198 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2200 // this final code is shared
2202 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2203 VectorScale(lightcolorbase, colorscale, color2);
2204 GL_LockArrays(firstvertex, numvertices);
2205 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2207 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2208 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2210 c_rt_lighttris += numtriangles;
2212 GL_LockArrays(0, 0);
2214 if (specularscale && glosstexture != r_texture_black)
2216 // FIXME: detect blendsquare!
2217 //if (gl_support_blendsquare)
2219 colorscale = specularscale;
2221 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2223 // 2/0/0/1/2 3D combine blendsquare path
2224 memset(&m, 0, sizeof(m));
2225 m.pointer_vertex = vertex3f;
2226 m.tex[0] = R_GetTexture(bumptexture);
2227 m.pointer_texcoord[0] = texcoord2f;
2228 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2229 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2230 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2231 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);
2233 GL_ColorMask(0,0,0,1);
2234 // this squares the result
2235 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2236 GL_LockArrays(firstvertex, numvertices);
2237 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2238 GL_LockArrays(0, 0);
2240 c_rt_lighttris += numtriangles;
2242 memset(&m, 0, sizeof(m));
2243 m.pointer_vertex = vertex3f;
2245 GL_LockArrays(firstvertex, numvertices);
2246 // square alpha in framebuffer a few times to make it shiny
2247 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2248 // these comments are a test run through this math for intensity 0.5
2249 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2250 // 0.25 * 0.25 = 0.0625 (this is another pass)
2251 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2252 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2254 c_rt_lighttris += numtriangles;
2255 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2257 c_rt_lighttris += numtriangles;
2258 GL_LockArrays(0, 0);
2260 memset(&m, 0, sizeof(m));
2261 m.pointer_vertex = vertex3f;
2262 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2264 m.pointer_texcoord3f[0] = vertex3f;
2265 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2267 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2268 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2271 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2272 GL_LockArrays(firstvertex, numvertices);
2273 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2274 GL_LockArrays(0, 0);
2276 c_rt_lighttris += numtriangles;
2278 memset(&m, 0, sizeof(m));
2279 m.pointer_vertex = vertex3f;
2280 m.tex[0] = R_GetTexture(glosstexture);
2281 m.pointer_texcoord[0] = texcoord2f;
2282 if (r_shadow_lightcubemap != r_texture_whitecube)
2284 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2286 m.pointer_texcoord3f[1] = vertex3f;
2287 m.texmatrix[1] = r_shadow_entitytolight;
2289 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2290 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2293 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2295 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2297 // 2/0/0/2 3D combine blendsquare path
2298 memset(&m, 0, sizeof(m));
2299 m.pointer_vertex = vertex3f;
2300 m.tex[0] = R_GetTexture(bumptexture);
2301 m.pointer_texcoord[0] = texcoord2f;
2302 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2303 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2304 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2305 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);
2307 GL_ColorMask(0,0,0,1);
2308 // this squares the result
2309 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2310 GL_LockArrays(firstvertex, numvertices);
2311 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2312 GL_LockArrays(0, 0);
2314 c_rt_lighttris += numtriangles;
2316 memset(&m, 0, sizeof(m));
2317 m.pointer_vertex = vertex3f;
2319 GL_LockArrays(firstvertex, numvertices);
2320 // square alpha in framebuffer a few times to make it shiny
2321 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2322 // these comments are a test run through this math for intensity 0.5
2323 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2324 // 0.25 * 0.25 = 0.0625 (this is another pass)
2325 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2326 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2328 c_rt_lighttris += numtriangles;
2329 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2331 c_rt_lighttris += numtriangles;
2332 GL_LockArrays(0, 0);
2334 memset(&m, 0, sizeof(m));
2335 m.pointer_vertex = vertex3f;
2336 m.tex[0] = R_GetTexture(glosstexture);
2337 m.pointer_texcoord[0] = texcoord2f;
2338 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2340 m.pointer_texcoord3f[1] = vertex3f;
2341 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2343 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2344 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2346 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2350 // 2/0/0/2/2 2D combine blendsquare path
2351 memset(&m, 0, sizeof(m));
2352 m.pointer_vertex = vertex3f;
2353 m.tex[0] = R_GetTexture(bumptexture);
2354 m.pointer_texcoord[0] = texcoord2f;
2355 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2356 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2357 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2358 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);
2360 GL_ColorMask(0,0,0,1);
2361 // this squares the result
2362 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2363 GL_LockArrays(firstvertex, numvertices);
2364 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2365 GL_LockArrays(0, 0);
2367 c_rt_lighttris += numtriangles;
2369 memset(&m, 0, sizeof(m));
2370 m.pointer_vertex = vertex3f;
2372 GL_LockArrays(firstvertex, numvertices);
2373 // square alpha in framebuffer a few times to make it shiny
2374 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2375 // these comments are a test run through this math for intensity 0.5
2376 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2377 // 0.25 * 0.25 = 0.0625 (this is another pass)
2378 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2379 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2381 c_rt_lighttris += numtriangles;
2382 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2384 c_rt_lighttris += numtriangles;
2385 GL_LockArrays(0, 0);
2387 memset(&m, 0, sizeof(m));
2388 m.pointer_vertex = vertex3f;
2389 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2391 m.pointer_texcoord3f[0] = vertex3f;
2392 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2394 m.pointer_texcoord[0] = varray_texcoord2f[0];
2395 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2397 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2399 m.pointer_texcoord3f[1] = vertex3f;
2400 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2402 m.pointer_texcoord[1] = varray_texcoord2f[1];
2403 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2406 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2407 GL_LockArrays(firstvertex, numvertices);
2408 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2409 GL_LockArrays(0, 0);
2411 c_rt_lighttris += numtriangles;
2413 memset(&m, 0, sizeof(m));
2414 m.pointer_vertex = vertex3f;
2415 m.tex[0] = R_GetTexture(glosstexture);
2416 m.pointer_texcoord[0] = texcoord2f;
2417 if (r_shadow_lightcubemap != r_texture_whitecube)
2419 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2421 m.pointer_texcoord3f[1] = vertex3f;
2422 m.texmatrix[1] = r_shadow_entitytolight;
2424 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2425 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2428 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2431 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2432 VectorScale(lightcolorbase, colorscale, color2);
2433 GL_LockArrays(firstvertex, numvertices);
2434 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2436 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2437 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2439 c_rt_lighttris += numtriangles;
2441 GL_LockArrays(0, 0);
2445 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
2447 // TODO: add direct pants/shirt rendering
2448 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2449 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
2450 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2451 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
2452 if (r_shadow_rtlight->ambientscale)
2454 GL_BlendFunc(GL_ONE, GL_ONE);
2455 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
2456 memset(&m, 0, sizeof(m));
2457 m.pointer_vertex = vertex3f;
2458 m.tex[0] = R_GetTexture(basetexture);
2459 m.pointer_texcoord[0] = texcoord2f;
2460 if (r_textureunits.integer >= 2)
2463 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2465 m.pointer_texcoord3f[1] = vertex3f;
2466 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2468 m.pointer_texcoord[1] = varray_texcoord2f[1];
2469 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2471 if (r_textureunits.integer >= 3)
2473 // Geforce3/Radeon class but not using dot3
2474 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2476 m.pointer_texcoord3f[2] = vertex3f;
2477 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2479 m.pointer_texcoord[2] = varray_texcoord2f[2];
2480 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2484 if (r_textureunits.integer >= 3)
2485 m.pointer_color = NULL;
2487 m.pointer_color = varray_color4f;
2489 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2491 color[0] = bound(0, color2[0], 1);
2492 color[1] = bound(0, color2[1], 1);
2493 color[2] = bound(0, color2[2], 1);
2494 if (r_textureunits.integer >= 3)
2495 GL_Color(color[0], color[1], color[2], 1);
2496 else if (r_textureunits.integer >= 2)
2497 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2499 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2500 GL_LockArrays(firstvertex, numvertices);
2501 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2502 GL_LockArrays(0, 0);
2504 c_rt_lighttris += numtriangles;
2507 if (r_shadow_rtlight->diffusescale)
2509 GL_BlendFunc(GL_ONE, GL_ONE);
2510 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
2511 memset(&m, 0, sizeof(m));
2512 m.pointer_vertex = vertex3f;
2513 m.pointer_color = varray_color4f;
2514 m.tex[0] = R_GetTexture(basetexture);
2515 m.pointer_texcoord[0] = texcoord2f;
2516 if (r_textureunits.integer >= 2)
2519 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2521 m.pointer_texcoord3f[1] = vertex3f;
2522 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2524 m.pointer_texcoord[1] = varray_texcoord2f[1];
2525 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2527 if (r_textureunits.integer >= 3)
2529 // Geforce3/Radeon class but not using dot3
2530 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2532 m.pointer_texcoord3f[2] = vertex3f;
2533 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2535 m.pointer_texcoord[2] = varray_texcoord2f[2];
2536 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2541 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2543 color[0] = bound(0, color2[0], 1);
2544 color[1] = bound(0, color2[1], 1);
2545 color[2] = bound(0, color2[2], 1);
2546 if (r_textureunits.integer >= 3)
2547 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2548 else if (r_textureunits.integer >= 2)
2549 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2551 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2552 GL_LockArrays(firstvertex, numvertices);
2553 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2554 GL_LockArrays(0, 0);
2556 c_rt_lighttris += numtriangles;
2562 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2566 R_RTLight_Uncompile(rtlight);
2567 memset(rtlight, 0, sizeof(*rtlight));
2569 VectorCopy(light->origin, rtlight->shadoworigin);
2570 VectorCopy(light->color, rtlight->color);
2571 rtlight->radius = light->radius;
2572 //rtlight->cullradius = rtlight->radius;
2573 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2574 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2575 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2576 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2577 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2578 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2579 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2580 rtlight->cubemapname[0] = 0;
2581 if (light->cubemapname[0])
2582 strcpy(rtlight->cubemapname, light->cubemapname);
2583 else if (light->cubemapnum > 0)
2584 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2585 rtlight->shadow = light->shadow;
2586 rtlight->corona = light->corona;
2587 rtlight->style = light->style;
2588 rtlight->isstatic = isstatic;
2589 rtlight->coronasizescale = light->coronasizescale;
2590 rtlight->ambientscale = light->ambientscale;
2591 rtlight->diffusescale = light->diffusescale;
2592 rtlight->specularscale = light->specularscale;
2593 rtlight->flags = light->flags;
2594 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2595 // ConcatScale won't work here because this needs to scale rotate and
2596 // translate, not just rotate
2597 scale = 1.0f / rtlight->radius;
2598 for (k = 0;k < 3;k++)
2599 for (j = 0;j < 4;j++)
2600 rtlight->matrix_worldtolight.m[k][j] *= scale;
2602 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2603 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2604 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2605 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2608 // compiles rtlight geometry
2609 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2610 void R_RTLight_Compile(rtlight_t *rtlight)
2612 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2613 entity_render_t *ent = r_refdef.worldentity;
2614 model_t *model = r_refdef.worldmodel;
2617 // compile the light
2618 rtlight->compiled = true;
2619 rtlight->static_numleafs = 0;
2620 rtlight->static_numleafpvsbytes = 0;
2621 rtlight->static_leaflist = NULL;
2622 rtlight->static_leafpvs = NULL;
2623 rtlight->static_numsurfaces = 0;
2624 rtlight->static_surfacelist = NULL;
2625 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2626 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2627 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2628 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2629 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2630 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2632 if (model && model->GetLightInfo)
2634 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2635 r_shadow_compilingrtlight = rtlight;
2636 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->brush.num_surfaces);
2637 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);
2638 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2639 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2640 rtlight->static_numleafs = numleafs;
2641 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2642 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2643 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2644 rtlight->static_numsurfaces = numsurfaces;
2645 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2647 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2648 if (numleafpvsbytes)
2649 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2651 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2652 if (model->DrawShadowVolume && rtlight->shadow)
2654 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2655 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2656 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2658 if (model->DrawLight)
2660 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2661 model->DrawLight(ent, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
2662 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2664 // switch back to rendering when DrawShadowVolume or DrawLight is called
2665 r_shadow_compilingrtlight = NULL;
2669 // use smallest available cullradius - box radius or light radius
2670 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2671 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2675 if (rtlight->static_meshchain_shadow)
2678 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2681 shadowtris += mesh->numtriangles;
2687 if (rtlight->static_meshchain_light)
2690 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2693 lighttris += mesh->numtriangles;
2697 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);
2700 void R_RTLight_Uncompile(rtlight_t *rtlight)
2702 if (rtlight->compiled)
2704 if (rtlight->static_meshchain_shadow)
2705 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2706 rtlight->static_meshchain_shadow = NULL;
2707 if (rtlight->static_meshchain_light)
2708 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2709 rtlight->static_meshchain_light = NULL;
2710 // these allocations are grouped
2711 if (rtlight->static_leaflist)
2712 Mem_Free(rtlight->static_leaflist);
2713 rtlight->static_numleafs = 0;
2714 rtlight->static_numleafpvsbytes = 0;
2715 rtlight->static_leaflist = NULL;
2716 rtlight->static_leafpvs = NULL;
2717 rtlight->static_numsurfaces = 0;
2718 rtlight->static_surfacelist = NULL;
2719 rtlight->compiled = false;
2723 void R_Shadow_UncompileWorldLights(void)
2726 for (light = r_shadow_worldlightchain;light;light = light->next)
2727 R_RTLight_Uncompile(&light->rtlight);
2730 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2732 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2733 vec_t relativeshadowradius;
2734 if (ent == r_refdef.worldentity)
2736 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2739 R_Mesh_Matrix(&ent->matrix);
2740 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2742 R_Mesh_VertexPointer(mesh->vertex3f);
2743 GL_LockArrays(0, mesh->numverts);
2744 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2746 // increment stencil if backface is behind depthbuffer
2747 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2748 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2749 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2750 c_rtcached_shadowmeshes++;
2751 c_rtcached_shadowtris += mesh->numtriangles;
2752 // decrement stencil if frontface is behind depthbuffer
2753 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2754 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2756 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2757 c_rtcached_shadowmeshes++;
2758 c_rtcached_shadowtris += mesh->numtriangles;
2759 GL_LockArrays(0, 0);
2762 else if (numsurfaces)
2764 R_Mesh_Matrix(&ent->matrix);
2765 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2770 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2771 relativeshadowradius = rtlight->radius / ent->scale;
2772 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2773 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2774 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2775 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2776 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2777 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2778 R_Mesh_Matrix(&ent->matrix);
2779 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2783 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2786 // set up properties for rendering light onto this entity
2787 r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2788 r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2789 r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2790 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2791 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2792 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2793 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2794 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2795 R_Mesh_Matrix(&ent->matrix);
2796 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2798 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2799 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2800 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2801 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2803 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2806 if (ent == r_refdef.worldentity)
2808 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2810 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2811 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);
2814 ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2817 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2820 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2825 int numleafs, numsurfaces;
2826 int *leaflist, *surfacelist;
2828 int numlightentities;
2829 int numshadowentities;
2830 entity_render_t *lightentities[MAX_EDICTS];
2831 entity_render_t *shadowentities[MAX_EDICTS];
2833 // skip lights that don't light (corona only lights)
2834 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2837 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2838 VectorScale(rtlight->color, f, lightcolor);
2839 if (VectorLength2(lightcolor) < 0.01)
2842 if (rtlight->selected)
2844 f = 2 + sin(realtime * M_PI * 4.0);
2845 VectorScale(lightcolor, f, lightcolor);
2849 // loading is done before visibility checks because loading should happen
2850 // all at once at the start of a level, not when it stalls gameplay.
2851 // (especially important to benchmarks)
2853 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2854 R_RTLight_Compile(rtlight);
2856 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2858 // if the light box is offscreen, skip it
2859 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2862 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2864 // compiled light, world available and can receive realtime lighting
2865 // retrieve leaf information
2866 numleafs = rtlight->static_numleafs;
2867 leaflist = rtlight->static_leaflist;
2868 leafpvs = rtlight->static_leafpvs;
2869 numsurfaces = rtlight->static_numsurfaces;
2870 surfacelist = rtlight->static_surfacelist;
2872 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2874 // dynamic light, world available and can receive realtime lighting
2875 // calculate lit surfaces and leafs
2876 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
2877 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);
2878 leaflist = r_shadow_buffer_leaflist;
2879 leafpvs = r_shadow_buffer_leafpvs;
2880 surfacelist = r_shadow_buffer_surfacelist;
2881 // if the reduced leaf bounds are offscreen, skip it
2882 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2894 // check if light is illuminating any visible leafs
2897 for (i = 0;i < numleafs;i++)
2898 if (r_worldleafvisible[leaflist[i]])
2903 // set up a scissor rectangle for this light
2904 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2907 numlightentities = 0;
2909 lightentities[numlightentities++] = r_refdef.worldentity;
2910 numshadowentities = 0;
2912 shadowentities[numshadowentities++] = r_refdef.worldentity;
2913 if (r_drawentities.integer)
2915 for (i = 0;i < r_refdef.numentities;i++)
2917 entity_render_t *ent = r_refdef.entities[i];
2918 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2920 && !(ent->flags & RENDER_TRANSPARENT)
2921 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2923 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2924 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2925 shadowentities[numshadowentities++] = ent;
2926 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2927 lightentities[numlightentities++] = ent;
2932 // return if there's nothing at all to light
2933 if (!numlightentities)
2936 R_Shadow_Stage_ActiveLight(rtlight);
2940 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2943 R_Shadow_Stage_StencilShadowVolumes();
2944 for (i = 0;i < numshadowentities;i++)
2945 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2948 if (numlightentities && !visible)
2950 R_Shadow_Stage_Lighting(usestencil);
2951 for (i = 0;i < numlightentities;i++)
2952 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2955 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2957 R_Shadow_Stage_VisibleShadowVolumes();
2958 for (i = 0;i < numshadowentities;i++)
2959 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2962 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2964 R_Shadow_Stage_VisibleLighting(usestencil);
2965 for (i = 0;i < numlightentities;i++)
2966 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2970 void R_ShadowVolumeLighting(qboolean visible)
2975 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2976 R_Shadow_EditLights_Reload_f();
2978 R_Shadow_Stage_Begin();
2980 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2981 if (r_shadow_debuglight.integer >= 0)
2983 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2984 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2985 R_DrawRTLight(&light->rtlight, visible);
2988 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2989 if (light->flags & flag)
2990 R_DrawRTLight(&light->rtlight, visible);
2992 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2993 R_DrawRTLight(&light->rtlight, visible);
2995 R_Shadow_Stage_End();
2998 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2999 typedef struct suffixinfo_s
3002 qboolean flipx, flipy, flipdiagonal;
3005 static suffixinfo_t suffix[3][6] =
3008 {"px", false, false, false},
3009 {"nx", false, false, false},
3010 {"py", false, false, false},
3011 {"ny", false, false, false},
3012 {"pz", false, false, false},
3013 {"nz", false, false, false}
3016 {"posx", false, false, false},
3017 {"negx", false, false, false},
3018 {"posy", false, false, false},
3019 {"negy", false, false, false},
3020 {"posz", false, false, false},
3021 {"negz", false, false, false}
3024 {"rt", true, false, true},
3025 {"lf", false, true, true},
3026 {"ft", true, true, false},
3027 {"bk", false, false, false},
3028 {"up", true, false, true},
3029 {"dn", true, false, true}
3033 static int componentorder[4] = {0, 1, 2, 3};
3035 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3037 int i, j, cubemapsize;
3038 qbyte *cubemappixels, *image_rgba;
3039 rtexture_t *cubemaptexture;
3041 // must start 0 so the first loadimagepixels has no requested width/height
3043 cubemappixels = NULL;
3044 cubemaptexture = NULL;
3045 // keep trying different suffix groups (posx, px, rt) until one loads
3046 for (j = 0;j < 3 && !cubemappixels;j++)
3048 // load the 6 images in the suffix group
3049 for (i = 0;i < 6;i++)
3051 // generate an image name based on the base and and suffix
3052 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3054 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3056 // an image loaded, make sure width and height are equal
3057 if (image_width == image_height)
3059 // if this is the first image to load successfully, allocate the cubemap memory
3060 if (!cubemappixels && image_width >= 1)
3062 cubemapsize = image_width;
3063 // note this clears to black, so unavailable sides are black
3064 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3066 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3068 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);
3071 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3073 Mem_Free(image_rgba);
3077 // if a cubemap loaded, upload it
3080 if (!r_shadow_filters_texturepool)
3081 r_shadow_filters_texturepool = R_AllocTexturePool();
3082 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3083 Mem_Free(cubemappixels);
3087 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3088 for (j = 0;j < 3;j++)
3089 for (i = 0;i < 6;i++)
3090 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3091 Con_Print(" and was unable to find any of them.\n");
3093 return cubemaptexture;
3096 rtexture_t *R_Shadow_Cubemap(const char *basename)
3099 for (i = 0;i < numcubemaps;i++)
3100 if (!strcasecmp(cubemaps[i].basename, basename))
3101 return cubemaps[i].texture;
3102 if (i >= MAX_CUBEMAPS)
3103 return r_texture_whitecube;
3105 strcpy(cubemaps[i].basename, basename);
3106 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3107 return cubemaps[i].texture;
3110 void R_Shadow_FreeCubemaps(void)
3113 R_FreeTexturePool(&r_shadow_filters_texturepool);
3116 dlight_t *R_Shadow_NewWorldLight(void)
3119 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3120 light->next = r_shadow_worldlightchain;
3121 r_shadow_worldlightchain = light;
3125 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)
3127 VectorCopy(origin, light->origin);
3128 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3129 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3130 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3131 light->color[0] = max(color[0], 0);
3132 light->color[1] = max(color[1], 0);
3133 light->color[2] = max(color[2], 0);
3134 light->radius = max(radius, 0);
3135 light->style = style;
3136 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3138 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3141 light->shadow = shadowenable;
3142 light->corona = corona;
3145 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3146 light->coronasizescale = coronasizescale;
3147 light->ambientscale = ambientscale;
3148 light->diffusescale = diffusescale;
3149 light->specularscale = specularscale;
3150 light->flags = flags;
3151 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3153 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3156 void R_Shadow_FreeWorldLight(dlight_t *light)
3158 dlight_t **lightpointer;
3159 R_RTLight_Uncompile(&light->rtlight);
3160 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3161 if (*lightpointer != light)
3162 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3163 *lightpointer = light->next;
3167 void R_Shadow_ClearWorldLights(void)
3169 while (r_shadow_worldlightchain)
3170 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3171 r_shadow_selectedlight = NULL;
3172 R_Shadow_FreeCubemaps();
3175 void R_Shadow_SelectLight(dlight_t *light)
3177 if (r_shadow_selectedlight)
3178 r_shadow_selectedlight->selected = false;
3179 r_shadow_selectedlight = light;
3180 if (r_shadow_selectedlight)
3181 r_shadow_selectedlight->selected = true;
3184 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3186 float scale = r_editlights_cursorgrid.value * 0.5f;
3187 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);
3190 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3193 const dlight_t *light;
3196 if (light->selected)
3197 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3200 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);
3203 void R_Shadow_DrawLightSprites(void)
3209 for (i = 0;i < 5;i++)
3211 lighttextures[i] = NULL;
3212 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3213 lighttextures[i] = pic->tex;
3216 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3217 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3218 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3221 void R_Shadow_SelectLightInView(void)
3223 float bestrating, rating, temp[3];
3224 dlight_t *best, *light;
3227 for (light = r_shadow_worldlightchain;light;light = light->next)
3229 VectorSubtract(light->origin, r_vieworigin, temp);
3230 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3233 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3234 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3236 bestrating = rating;
3241 R_Shadow_SelectLight(best);
3244 void R_Shadow_LoadWorldLights(void)
3246 int n, a, style, shadow, flags;
3247 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3248 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3249 if (r_refdef.worldmodel == NULL)
3251 Con_Print("No map loaded.\n");
3254 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3255 strlcat (name, ".rtlights", sizeof (name));
3256 lightsstring = FS_LoadFile(name, tempmempool, false);
3266 for (;COM_Parse(t, true) && strcmp(
3267 if (COM_Parse(t, true))
3269 if (com_token[0] == '!')
3272 origin[0] = atof(com_token+1);
3275 origin[0] = atof(com_token);
3280 while (*s && *s != '\n' && *s != '\r')
3286 // check for modifier flags
3293 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);
3296 flags = LIGHTFLAG_REALTIMEMODE;
3304 coronasizescale = 0.25f;
3306 VectorClear(angles);
3309 if (a < 9 || !strcmp(cubemapname, "\"\""))
3311 // remove quotes on cubemapname
3312 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3314 cubemapname[strlen(cubemapname)-1] = 0;
3315 strcpy(cubemapname, cubemapname + 1);
3319 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);
3322 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3323 radius *= r_editlights_rtlightssizescale.value;
3324 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3332 Con_Printf("invalid rtlights file \"%s\"\n", name);
3333 Mem_Free(lightsstring);
3337 void R_Shadow_SaveWorldLights(void)
3340 int bufchars, bufmaxchars;
3342 char name[MAX_QPATH];
3344 if (!r_shadow_worldlightchain)
3346 if (r_refdef.worldmodel == NULL)
3348 Con_Print("No map loaded.\n");
3351 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3352 strlcat (name, ".rtlights", sizeof (name));
3353 bufchars = bufmaxchars = 0;
3355 for (light = r_shadow_worldlightchain;light;light = light->next)
3357 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3358 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);
3359 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3360 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]);
3362 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);
3363 if (bufchars + (int) strlen(line) > bufmaxchars)
3365 bufmaxchars = bufchars + strlen(line) + 2048;
3367 buf = Mem_Alloc(tempmempool, bufmaxchars);
3371 memcpy(buf, oldbuf, bufchars);
3377 memcpy(buf + bufchars, line, strlen(line));
3378 bufchars += strlen(line);
3382 FS_WriteFile(name, buf, bufchars);
3387 void R_Shadow_LoadLightsFile(void)
3390 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3391 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3392 if (r_refdef.worldmodel == NULL)
3394 Con_Print("No map loaded.\n");
3397 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3398 strlcat (name, ".lights", sizeof (name));
3399 lightsstring = FS_LoadFile(name, tempmempool, false);
3407 while (*s && *s != '\n' && *s != '\r')
3413 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);
3417 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);
3420 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3421 radius = bound(15, radius, 4096);
3422 VectorScale(color, (2.0f / (8388608.0f)), color);
3423 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3431 Con_Printf("invalid lights file \"%s\"\n", name);
3432 Mem_Free(lightsstring);
3436 // tyrlite/hmap2 light types in the delay field
3437 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3439 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3441 int entnum, style, islight, skin, pflags, effects, type, n;
3444 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3445 char key[256], value[1024];
3447 if (r_refdef.worldmodel == NULL)
3449 Con_Print("No map loaded.\n");
3452 // try to load a .ent file first
3453 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3454 strlcat (key, ".ent", sizeof (key));
3455 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3456 // and if that is not found, fall back to the bsp file entity string
3458 data = r_refdef.worldmodel->brush.entities;
3461 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3463 type = LIGHTTYPE_MINUSX;
3464 origin[0] = origin[1] = origin[2] = 0;
3465 originhack[0] = originhack[1] = originhack[2] = 0;
3466 angles[0] = angles[1] = angles[2] = 0;
3467 color[0] = color[1] = color[2] = 1;
3468 light[0] = light[1] = light[2] = 1;light[3] = 300;
3469 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3479 if (!COM_ParseToken(&data, false))
3481 if (com_token[0] == '}')
3482 break; // end of entity
3483 if (com_token[0] == '_')
3484 strcpy(key, com_token + 1);
3486 strcpy(key, com_token);
3487 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3488 key[strlen(key)-1] = 0;
3489 if (!COM_ParseToken(&data, false))
3491 strcpy(value, com_token);
3493 // now that we have the key pair worked out...
3494 if (!strcmp("light", key))
3496 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3500 light[0] = vec[0] * (1.0f / 256.0f);
3501 light[1] = vec[0] * (1.0f / 256.0f);
3502 light[2] = vec[0] * (1.0f / 256.0f);
3508 light[0] = vec[0] * (1.0f / 255.0f);
3509 light[1] = vec[1] * (1.0f / 255.0f);
3510 light[2] = vec[2] * (1.0f / 255.0f);
3514 else if (!strcmp("delay", key))
3516 else if (!strcmp("origin", key))
3517 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3518 else if (!strcmp("angle", key))
3519 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3520 else if (!strcmp("angles", key))
3521 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3522 else if (!strcmp("color", key))
3523 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3524 else if (!strcmp("wait", key))
3525 fadescale = atof(value);
3526 else if (!strcmp("classname", key))
3528 if (!strncmp(value, "light", 5))
3531 if (!strcmp(value, "light_fluoro"))
3536 overridecolor[0] = 1;
3537 overridecolor[1] = 1;
3538 overridecolor[2] = 1;
3540 if (!strcmp(value, "light_fluorospark"))
3545 overridecolor[0] = 1;
3546 overridecolor[1] = 1;
3547 overridecolor[2] = 1;
3549 if (!strcmp(value, "light_globe"))
3554 overridecolor[0] = 1;
3555 overridecolor[1] = 0.8;
3556 overridecolor[2] = 0.4;
3558 if (!strcmp(value, "light_flame_large_yellow"))
3563 overridecolor[0] = 1;
3564 overridecolor[1] = 0.5;
3565 overridecolor[2] = 0.1;
3567 if (!strcmp(value, "light_flame_small_yellow"))
3572 overridecolor[0] = 1;
3573 overridecolor[1] = 0.5;
3574 overridecolor[2] = 0.1;
3576 if (!strcmp(value, "light_torch_small_white"))
3581 overridecolor[0] = 1;
3582 overridecolor[1] = 0.5;
3583 overridecolor[2] = 0.1;
3585 if (!strcmp(value, "light_torch_small_walltorch"))
3590 overridecolor[0] = 1;
3591 overridecolor[1] = 0.5;
3592 overridecolor[2] = 0.1;
3596 else if (!strcmp("style", key))
3597 style = atoi(value);
3598 else if (r_refdef.worldmodel->type == mod_brushq3)
3600 if (!strcmp("scale", key))
3601 lightscale = atof(value);
3602 if (!strcmp("fade", key))
3603 fadescale = atof(value);
3605 else if (!strcmp("skin", key))
3606 skin = (int)atof(value);
3607 else if (!strcmp("pflags", key))
3608 pflags = (int)atof(value);
3609 else if (!strcmp("effects", key))
3610 effects = (int)atof(value);
3614 if (lightscale <= 0)
3618 if (color[0] == color[1] && color[0] == color[2])
3620 color[0] *= overridecolor[0];
3621 color[1] *= overridecolor[1];
3622 color[2] *= overridecolor[2];
3624 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3625 color[0] = color[0] * light[0];
3626 color[1] = color[1] * light[1];
3627 color[2] = color[2] * light[2];
3630 case LIGHTTYPE_MINUSX:
3632 case LIGHTTYPE_RECIPX:
3634 VectorScale(color, (1.0f / 16.0f), color);
3636 case LIGHTTYPE_RECIPXX:
3638 VectorScale(color, (1.0f / 16.0f), color);
3641 case LIGHTTYPE_NONE:
3645 case LIGHTTYPE_MINUSXX:
3648 VectorAdd(origin, originhack, origin);
3650 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);
3653 Mem_Free(entfiledata);
3657 void R_Shadow_SetCursorLocationForView(void)
3660 vec3_t dest, endpos;
3662 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3663 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3664 if (trace.fraction < 1)
3666 dist = trace.fraction * r_editlights_cursordistance.value;
3667 push = r_editlights_cursorpushback.value;
3671 VectorMA(trace.endpos, push, r_viewforward, endpos);
3672 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3674 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3675 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3676 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3679 void R_Shadow_UpdateWorldLightSelection(void)
3681 if (r_editlights.integer)
3683 R_Shadow_SetCursorLocationForView();
3684 R_Shadow_SelectLightInView();
3685 R_Shadow_DrawLightSprites();
3688 R_Shadow_SelectLight(NULL);
3691 void R_Shadow_EditLights_Clear_f(void)
3693 R_Shadow_ClearWorldLights();
3696 void R_Shadow_EditLights_Reload_f(void)
3698 if (!r_refdef.worldmodel)
3700 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3701 R_Shadow_ClearWorldLights();
3702 R_Shadow_LoadWorldLights();
3703 if (r_shadow_worldlightchain == NULL)
3705 R_Shadow_LoadLightsFile();
3706 if (r_shadow_worldlightchain == NULL)
3707 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3711 void R_Shadow_EditLights_Save_f(void)
3713 if (!r_refdef.worldmodel)
3715 R_Shadow_SaveWorldLights();
3718 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3720 R_Shadow_ClearWorldLights();
3721 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3724 void R_Shadow_EditLights_ImportLightsFile_f(void)
3726 R_Shadow_ClearWorldLights();
3727 R_Shadow_LoadLightsFile();
3730 void R_Shadow_EditLights_Spawn_f(void)
3733 if (!r_editlights.integer)
3735 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3738 if (Cmd_Argc() != 1)
3740 Con_Print("r_editlights_spawn does not take parameters\n");
3743 color[0] = color[1] = color[2] = 1;
3744 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3747 void R_Shadow_EditLights_Edit_f(void)
3749 vec3_t origin, angles, color;
3750 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3751 int style, shadows, flags, normalmode, realtimemode;
3752 char cubemapname[1024];
3753 if (!r_editlights.integer)
3755 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3758 if (!r_shadow_selectedlight)
3760 Con_Print("No selected light.\n");
3763 VectorCopy(r_shadow_selectedlight->origin, origin);
3764 VectorCopy(r_shadow_selectedlight->angles, angles);
3765 VectorCopy(r_shadow_selectedlight->color, color);
3766 radius = r_shadow_selectedlight->radius;
3767 style = r_shadow_selectedlight->style;
3768 if (r_shadow_selectedlight->cubemapname)
3769 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3772 shadows = r_shadow_selectedlight->shadow;
3773 corona = r_shadow_selectedlight->corona;
3774 coronasizescale = r_shadow_selectedlight->coronasizescale;
3775 ambientscale = r_shadow_selectedlight->ambientscale;
3776 diffusescale = r_shadow_selectedlight->diffusescale;
3777 specularscale = r_shadow_selectedlight->specularscale;
3778 flags = r_shadow_selectedlight->flags;
3779 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3780 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3781 if (!strcmp(Cmd_Argv(1), "origin"))
3783 if (Cmd_Argc() != 5)
3785 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3788 origin[0] = atof(Cmd_Argv(2));
3789 origin[1] = atof(Cmd_Argv(3));
3790 origin[2] = atof(Cmd_Argv(4));
3792 else if (!strcmp(Cmd_Argv(1), "originx"))
3794 if (Cmd_Argc() != 3)
3796 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3799 origin[0] = atof(Cmd_Argv(2));
3801 else if (!strcmp(Cmd_Argv(1), "originy"))
3803 if (Cmd_Argc() != 3)
3805 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3808 origin[1] = atof(Cmd_Argv(2));
3810 else if (!strcmp(Cmd_Argv(1), "originz"))
3812 if (Cmd_Argc() != 3)
3814 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3817 origin[2] = atof(Cmd_Argv(2));
3819 else if (!strcmp(Cmd_Argv(1), "move"))
3821 if (Cmd_Argc() != 5)
3823 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3826 origin[0] += atof(Cmd_Argv(2));
3827 origin[1] += atof(Cmd_Argv(3));
3828 origin[2] += atof(Cmd_Argv(4));
3830 else if (!strcmp(Cmd_Argv(1), "movex"))
3832 if (Cmd_Argc() != 3)
3834 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3837 origin[0] += atof(Cmd_Argv(2));
3839 else if (!strcmp(Cmd_Argv(1), "movey"))
3841 if (Cmd_Argc() != 3)
3843 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3846 origin[1] += atof(Cmd_Argv(2));
3848 else if (!strcmp(Cmd_Argv(1), "movez"))
3850 if (Cmd_Argc() != 3)
3852 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3855 origin[2] += atof(Cmd_Argv(2));
3857 else if (!strcmp(Cmd_Argv(1), "angles"))
3859 if (Cmd_Argc() != 5)
3861 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3864 angles[0] = atof(Cmd_Argv(2));
3865 angles[1] = atof(Cmd_Argv(3));
3866 angles[2] = atof(Cmd_Argv(4));
3868 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3870 if (Cmd_Argc() != 3)
3872 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3875 angles[0] = atof(Cmd_Argv(2));
3877 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3879 if (Cmd_Argc() != 3)
3881 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3884 angles[1] = atof(Cmd_Argv(2));
3886 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3888 if (Cmd_Argc() != 3)
3890 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3893 angles[2] = atof(Cmd_Argv(2));
3895 else if (!strcmp(Cmd_Argv(1), "color"))
3897 if (Cmd_Argc() != 5)
3899 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3902 color[0] = atof(Cmd_Argv(2));
3903 color[1] = atof(Cmd_Argv(3));
3904 color[2] = atof(Cmd_Argv(4));
3906 else if (!strcmp(Cmd_Argv(1), "radius"))
3908 if (Cmd_Argc() != 3)
3910 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3913 radius = atof(Cmd_Argv(2));
3915 else if (!strcmp(Cmd_Argv(1), "style"))
3917 if (Cmd_Argc() != 3)
3919 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3922 style = atoi(Cmd_Argv(2));
3924 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3928 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3931 if (Cmd_Argc() == 3)
3932 strcpy(cubemapname, Cmd_Argv(2));
3936 else if (!strcmp(Cmd_Argv(1), "shadows"))
3938 if (Cmd_Argc() != 3)
3940 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3943 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3945 else if (!strcmp(Cmd_Argv(1), "corona"))
3947 if (Cmd_Argc() != 3)
3949 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3952 corona = atof(Cmd_Argv(2));
3954 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3956 if (Cmd_Argc() != 3)
3958 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3961 coronasizescale = atof(Cmd_Argv(2));
3963 else if (!strcmp(Cmd_Argv(1), "ambient"))
3965 if (Cmd_Argc() != 3)
3967 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3970 ambientscale = atof(Cmd_Argv(2));
3972 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3974 if (Cmd_Argc() != 3)
3976 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3979 diffusescale = atof(Cmd_Argv(2));
3981 else if (!strcmp(Cmd_Argv(1), "specular"))
3983 if (Cmd_Argc() != 3)
3985 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3988 specularscale = atof(Cmd_Argv(2));
3990 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3992 if (Cmd_Argc() != 3)
3994 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3997 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3999 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4001 if (Cmd_Argc() != 3)
4003 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4006 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4010 Con_Print("usage: r_editlights_edit [property] [value]\n");
4011 Con_Print("Selected light's properties:\n");
4012 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4013 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4014 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4015 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4016 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4017 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4018 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4019 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4020 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4021 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4022 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4023 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4024 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4025 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4028 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4029 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4032 void R_Shadow_EditLights_EditAll_f(void)
4036 if (!r_editlights.integer)
4038 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4042 for (light = r_shadow_worldlightchain;light;light = light->next)
4044 R_Shadow_SelectLight(light);
4045 R_Shadow_EditLights_Edit_f();
4049 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4051 int lightnumber, lightcount;
4055 if (!r_editlights.integer)
4061 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4062 if (light == r_shadow_selectedlight)
4063 lightnumber = lightcount;
4064 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;
4065 if (r_shadow_selectedlight == NULL)
4067 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4068 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;
4069 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;
4070 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;
4071 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4072 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4073 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4074 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;
4075 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4076 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4077 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4078 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4079 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4080 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;
4081 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;
4084 void R_Shadow_EditLights_ToggleShadow_f(void)
4086 if (!r_editlights.integer)
4088 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4091 if (!r_shadow_selectedlight)
4093 Con_Print("No selected light.\n");
4096 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
4099 void R_Shadow_EditLights_ToggleCorona_f(void)
4101 if (!r_editlights.integer)
4103 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4106 if (!r_shadow_selectedlight)
4108 Con_Print("No selected light.\n");
4111 R_Shadow_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);
4114 void R_Shadow_EditLights_Remove_f(void)
4116 if (!r_editlights.integer)
4118 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4121 if (!r_shadow_selectedlight)
4123 Con_Print("No selected light.\n");
4126 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4127 r_shadow_selectedlight = NULL;
4130 void R_Shadow_EditLights_Help_f(void)
4133 "Documentation on r_editlights system:\n"
4135 "r_editlights : enable/disable editing mode\n"
4136 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4137 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4138 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4139 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4140 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4141 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4142 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4144 "r_editlights_help : this help\n"
4145 "r_editlights_clear : remove all lights\n"
4146 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4147 "r_editlights_save : save to .rtlights file\n"
4148 "r_editlights_spawn : create a light with default settings\n"
4149 "r_editlights_edit command : edit selected light - more documentation below\n"
4150 "r_editlights_remove : remove selected light\n"
4151 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4152 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4153 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4155 "origin x y z : set light location\n"
4156 "originx x: set x component of light location\n"
4157 "originy y: set y component of light location\n"
4158 "originz z: set z component of light location\n"
4159 "move x y z : adjust light location\n"
4160 "movex x: adjust x component of light location\n"
4161 "movey y: adjust y component of light location\n"
4162 "movez z: adjust z component of light location\n"
4163 "angles x y z : set light angles\n"
4164 "anglesx x: set x component of light angles\n"
4165 "anglesy y: set y component of light angles\n"
4166 "anglesz z: set z component of light angles\n"
4167 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4168 "radius radius : set radius (size) of light\n"
4169 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4170 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4171 "shadows 1/0 : turn on/off shadows\n"
4172 "corona n : set corona intensity\n"
4173 "coronasize n : set corona size (0-1)\n"
4174 "ambient n : set ambient intensity (0-1)\n"
4175 "diffuse n : set diffuse intensity (0-1)\n"
4176 "specular n : set specular intensity (0-1)\n"
4177 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4178 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4179 "<nothing> : print light properties to console\n"
4183 void R_Shadow_EditLights_CopyInfo_f(void)
4185 if (!r_editlights.integer)
4187 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4190 if (!r_shadow_selectedlight)
4192 Con_Print("No selected light.\n");
4195 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4196 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4197 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4198 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4199 if (r_shadow_selectedlight->cubemapname)
4200 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4202 r_shadow_bufferlight.cubemapname[0] = 0;
4203 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4204 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4205 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4206 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4207 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4208 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4209 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4212 void R_Shadow_EditLights_PasteInfo_f(void)
4214 if (!r_editlights.integer)
4216 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4219 if (!r_shadow_selectedlight)
4221 Con_Print("No selected light.\n");
4224 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);
4227 void R_Shadow_EditLights_Init(void)
4229 Cvar_RegisterVariable(&r_editlights);
4230 Cvar_RegisterVariable(&r_editlights_cursordistance);
4231 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4232 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4233 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4234 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4235 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4236 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4237 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4238 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4239 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4240 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4241 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4242 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4243 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4244 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4245 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4246 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4247 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4248 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4249 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4250 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);