3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankwhitecubetexture;
159 // lights are reloaded when this changes
160 char r_shadow_mapname[MAX_QPATH];
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
165 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
166 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
167 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
168 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
169 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
170 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
171 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
172 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
173 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
174 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
175 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
176 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
177 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
178 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
179 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
180 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
181 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
182 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
183 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
184 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
185 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
186 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
187 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
188 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
189 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
190 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
191 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
192 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
193 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
194 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
195 cvar_t r_editlights = {0, "r_editlights", "0"};
196 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
197 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
198 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
199 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
200 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
201 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
202 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
204 float r_shadow_attenpower, r_shadow_attenscale;
206 rtlight_t *r_shadow_compilingrtlight;
207 dlight_t *r_shadow_worldlightchain;
208 dlight_t *r_shadow_selectedlight;
209 dlight_t r_shadow_bufferlight;
210 vec3_t r_editlights_cursorlocation;
212 rtexture_t *lighttextures[5];
214 extern int con_vislines;
216 typedef struct cubemapinfo_s
223 #define MAX_CUBEMAPS 256
224 static int numcubemaps;
225 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
227 #define SHADERPERMUTATION_SPECULAR (1<<0)
228 #define SHADERPERMUTATION_FOG (1<<1)
229 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
230 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
231 #define SHADERPERMUTATION_COUNT (1<<4)
233 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
235 void R_Shadow_UncompileWorldLights(void);
236 void R_Shadow_ClearWorldLights(void);
237 void R_Shadow_SaveWorldLights(void);
238 void R_Shadow_LoadWorldLights(void);
239 void R_Shadow_LoadLightsFile(void);
240 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
241 void R_Shadow_EditLights_Reload_f(void);
242 void R_Shadow_ValidateCvars(void);
243 static void R_Shadow_MakeTextures(void);
244 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
246 const char *builtinshader_light_vert =
247 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
248 "// written by Forest 'LordHavoc' Hale\n"
250 "uniform vec3 LightPosition;\n"
252 "varying vec2 TexCoord;\n"
253 "varying vec3 CubeVector;\n"
254 "varying vec3 LightVector;\n"
256 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
257 "uniform vec3 EyePosition;\n"
258 "varying vec3 EyeVector;\n"
261 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
265 " // copy the surface texcoord\n"
266 " TexCoord = gl_MultiTexCoord0.st;\n"
268 " // transform vertex position into light attenuation/cubemap space\n"
269 " // (-1 to +1 across the light box)\n"
270 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
272 " // transform unnormalized light direction into tangent space\n"
273 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
274 " // normalize it per pixel)\n"
275 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
276 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
277 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
278 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
280 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
281 " // transform unnormalized eye direction into tangent space\n"
282 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
283 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
284 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
285 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
288 " // transform vertex to camera space, using ftransform to match non-VS\n"
290 " gl_Position = ftransform();\n"
294 const char *builtinshader_light_frag =
295 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
296 "// written by Forest 'LordHavoc' Hale\n"
298 "uniform vec3 LightColor;\n"
300 "#ifdef USEOFFSETMAPPING\n"
301 "uniform float OffsetMapping_Scale;\n"
302 "uniform float OffsetMapping_Bias;\n"
304 "#ifdef USESPECULAR\n"
305 "uniform float SpecularPower;\n"
308 "uniform float FogRangeRecip;\n"
310 "uniform float AmbientScale;\n"
311 "uniform float DiffuseScale;\n"
312 "#ifdef USESPECULAR\n"
313 "uniform float SpecularScale;\n"
316 "uniform sampler2D Texture_Normal;\n"
317 "uniform sampler2D Texture_Color;\n"
318 "#ifdef USESPECULAR\n"
319 "uniform sampler2D Texture_Gloss;\n"
321 "#ifdef USECUBEFILTER\n"
322 "uniform samplerCube Texture_Cube;\n"
325 "uniform sampler2D Texture_FogMask;\n"
328 "varying vec2 TexCoord;\n"
329 "varying vec3 CubeVector;\n"
330 "varying vec3 LightVector;\n"
331 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
332 "varying vec3 EyeVector;\n"
339 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
340 " // center and sharp falloff at the edge, this is about the most efficient\n"
341 " // we can get away with as far as providing illumination.\n"
343 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
344 " // provide significant illumination, large = slow = pain.\n"
345 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
349 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
352 "#ifdef USEOFFSETMAPPING\n"
353 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
354 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
355 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
356 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
357 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
358 "#define TexCoord TexCoordOffset\n"
361 " // get the texels - with a blendmap we'd need to blend multiple here\n"
362 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
363 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
364 "#ifdef USESPECULAR\n"
365 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
368 " // calculate shading\n"
369 " vec3 diffusenormal = normalize(LightVector);\n"
370 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
371 "#ifdef USESPECULAR\n"
372 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
375 "#ifdef USECUBEFILTER\n"
376 " // apply light cubemap filter\n"
377 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
380 " // calculate fragment color\n"
381 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
385 void r_shadow_start(void)
388 // allocate vertex processing arrays
390 r_shadow_normalcubetexture = NULL;
391 r_shadow_attenuation2dtexture = NULL;
392 r_shadow_attenuation3dtexture = NULL;
393 r_shadow_blankwhitecubetexture = NULL;
394 r_shadow_texturepool = NULL;
395 r_shadow_filters_texturepool = NULL;
396 R_Shadow_ValidateCvars();
397 R_Shadow_MakeTextures();
398 maxshadowelements = 0;
399 shadowelements = NULL;
407 shadowmarklist = NULL;
409 r_shadow_buffer_numclusterpvsbytes = 0;
410 r_shadow_buffer_clusterpvs = NULL;
411 r_shadow_buffer_clusterlist = NULL;
412 r_shadow_buffer_numsurfacepvsbytes = 0;
413 r_shadow_buffer_surfacepvs = NULL;
414 r_shadow_buffer_surfacelist = NULL;
415 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
416 r_shadow_program_light[i] = 0;
417 if (gl_support_fragment_shader)
419 char *vertstring, *fragstring;
420 int vertstrings_count;
421 int fragstrings_count;
422 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
423 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
424 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
425 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
426 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
428 vertstrings_count = 0;
429 fragstrings_count = 0;
430 if (i & SHADERPERMUTATION_SPECULAR)
432 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
433 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
435 if (i & SHADERPERMUTATION_FOG)
437 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
438 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
440 if (i & SHADERPERMUTATION_CUBEFILTER)
442 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
443 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
445 if (i & SHADERPERMUTATION_OFFSETMAPPING)
447 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
448 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
450 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
451 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
452 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
453 if (!r_shadow_program_light[i])
455 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
458 qglUseProgramObjectARB(r_shadow_program_light[i]);
459 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
460 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
461 if (i & SHADERPERMUTATION_SPECULAR)
463 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
465 if (i & SHADERPERMUTATION_CUBEFILTER)
467 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
469 if (i & SHADERPERMUTATION_FOG)
471 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
474 qglUseProgramObjectARB(0);
476 Mem_Free(fragstring);
478 Mem_Free(vertstring);
482 void r_shadow_shutdown(void)
485 R_Shadow_UncompileWorldLights();
486 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
488 if (r_shadow_program_light[i])
490 GL_Backend_FreeProgram(r_shadow_program_light[i]);
491 r_shadow_program_light[i] = 0;
495 r_shadow_normalcubetexture = NULL;
496 r_shadow_attenuation2dtexture = NULL;
497 r_shadow_attenuation3dtexture = NULL;
498 r_shadow_blankwhitecubetexture = NULL;
499 R_FreeTexturePool(&r_shadow_texturepool);
500 R_FreeTexturePool(&r_shadow_filters_texturepool);
501 maxshadowelements = 0;
503 Mem_Free(shadowelements);
504 shadowelements = NULL;
507 Mem_Free(vertexupdate);
510 Mem_Free(vertexremap);
516 Mem_Free(shadowmark);
519 Mem_Free(shadowmarklist);
520 shadowmarklist = NULL;
522 r_shadow_buffer_numclusterpvsbytes = 0;
523 if (r_shadow_buffer_clusterpvs)
524 Mem_Free(r_shadow_buffer_clusterpvs);
525 r_shadow_buffer_clusterpvs = NULL;
526 if (r_shadow_buffer_clusterlist)
527 Mem_Free(r_shadow_buffer_clusterlist);
528 r_shadow_buffer_clusterlist = NULL;
529 r_shadow_buffer_numsurfacepvsbytes = 0;
530 if (r_shadow_buffer_surfacepvs)
531 Mem_Free(r_shadow_buffer_surfacepvs);
532 r_shadow_buffer_surfacepvs = NULL;
533 if (r_shadow_buffer_surfacelist)
534 Mem_Free(r_shadow_buffer_surfacelist);
535 r_shadow_buffer_surfacelist = NULL;
538 void r_shadow_newmap(void)
542 void R_Shadow_Help_f(void)
545 "Documentation on r_shadow system:\n"
547 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
548 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
549 "r_shadow_debuglight : render only this light number (-1 = all)\n"
550 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
551 "r_shadow_gloss2intensity : brightness of forced gloss\n"
552 "r_shadow_glossintensity : brightness of textured gloss\n"
553 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
554 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
555 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
556 "r_shadow_portallight : use portal visibility for static light precomputation\n"
557 "r_shadow_projectdistance : shadow volume projection distance\n"
558 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
559 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
560 "r_shadow_realtime_world : use high quality world lighting mode\n"
561 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
562 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
563 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
564 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
565 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
566 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
567 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
568 "r_shadow_scissor : use scissor optimization\n"
569 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
570 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
571 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
572 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
573 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
575 "r_shadow_help : this help\n"
579 void R_Shadow_Init(void)
581 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
582 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
583 Cvar_RegisterVariable(&r_shadow_cull);
584 Cvar_RegisterVariable(&r_shadow_debuglight);
585 Cvar_RegisterVariable(&r_shadow_gloss);
586 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
587 Cvar_RegisterVariable(&r_shadow_glossintensity);
588 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
589 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
590 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
591 Cvar_RegisterVariable(&r_shadow_portallight);
592 Cvar_RegisterVariable(&r_shadow_projectdistance);
593 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
594 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
595 Cvar_RegisterVariable(&r_shadow_realtime_world);
596 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
597 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
598 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
599 Cvar_RegisterVariable(&r_shadow_scissor);
600 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
601 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
602 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
603 Cvar_RegisterVariable(&r_shadow_staticworldlights);
604 Cvar_RegisterVariable(&r_shadow_texture3d);
605 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
606 Cvar_RegisterVariable(&r_shadow_glsl);
607 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
608 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
609 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
610 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
611 if (gamemode == GAME_TENEBRAE)
613 Cvar_SetValue("r_shadow_gloss", 2);
614 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
616 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
617 R_Shadow_EditLights_Init();
618 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
619 r_shadow_worldlightchain = NULL;
620 maxshadowelements = 0;
621 shadowelements = NULL;
629 shadowmarklist = NULL;
631 r_shadow_buffer_numclusterpvsbytes = 0;
632 r_shadow_buffer_clusterpvs = NULL;
633 r_shadow_buffer_clusterlist = NULL;
634 r_shadow_buffer_numsurfacepvsbytes = 0;
635 r_shadow_buffer_surfacepvs = NULL;
636 r_shadow_buffer_surfacelist = NULL;
637 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
640 matrix4x4_t matrix_attenuationxyz =
643 {0.5, 0.0, 0.0, 0.5},
644 {0.0, 0.5, 0.0, 0.5},
645 {0.0, 0.0, 0.5, 0.5},
650 matrix4x4_t matrix_attenuationz =
653 {0.0, 0.0, 0.5, 0.5},
654 {0.0, 0.0, 0.0, 0.5},
655 {0.0, 0.0, 0.0, 0.5},
660 int *R_Shadow_ResizeShadowElements(int numtris)
662 // make sure shadowelements is big enough for this volume
663 if (maxshadowelements < numtris * 24)
665 maxshadowelements = numtris * 24;
667 Mem_Free(shadowelements);
668 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
670 return shadowelements;
673 void R_Shadow_EnlargeClusterSurfaceBuffer(int numclusters, int numsurfaces)
675 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
676 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
677 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
679 if (r_shadow_buffer_clusterpvs)
680 Mem_Free(r_shadow_buffer_clusterpvs);
681 if (r_shadow_buffer_clusterlist)
682 Mem_Free(r_shadow_buffer_clusterlist);
683 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
684 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
685 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
687 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
689 if (r_shadow_buffer_surfacepvs)
690 Mem_Free(r_shadow_buffer_surfacepvs);
691 if (r_shadow_buffer_surfacelist)
692 Mem_Free(r_shadow_buffer_surfacelist);
693 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
694 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
695 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
699 void R_Shadow_PrepareShadowMark(int numtris)
701 // make sure shadowmark is big enough for this volume
702 if (maxshadowmark < numtris)
704 maxshadowmark = numtris;
706 Mem_Free(shadowmark);
708 Mem_Free(shadowmarklist);
709 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
710 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
714 // if shadowmarkcount wrapped we clear the array and adjust accordingly
715 if (shadowmarkcount == 0)
718 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
723 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)
726 int outtriangles = 0, outvertices = 0;
730 if (maxvertexupdate < innumvertices)
732 maxvertexupdate = innumvertices;
734 Mem_Free(vertexupdate);
736 Mem_Free(vertexremap);
737 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
738 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
742 if (vertexupdatenum == 0)
745 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
746 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
749 for (i = 0;i < numshadowmarktris;i++)
750 shadowmark[shadowmarktris[i]] = shadowmarkcount;
752 for (i = 0;i < numshadowmarktris;i++)
754 element = inelement3i + shadowmarktris[i] * 3;
755 // make sure the vertices are created
756 for (j = 0;j < 3;j++)
758 if (vertexupdate[element[j]] != vertexupdatenum)
760 float ratio, direction[3];
761 vertexupdate[element[j]] = vertexupdatenum;
762 vertexremap[element[j]] = outvertices;
763 vertex = invertex3f + element[j] * 3;
764 // project one copy of the vertex to the sphere radius of the light
765 // (FIXME: would projecting it to the light box be better?)
766 VectorSubtract(vertex, projectorigin, direction);
767 ratio = projectdistance / VectorLength(direction);
768 VectorCopy(vertex, outvertex3f);
769 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
776 for (i = 0;i < numshadowmarktris;i++)
778 int remappedelement[3];
780 const int *neighbortriangle;
782 markindex = shadowmarktris[i] * 3;
783 element = inelement3i + markindex;
784 neighbortriangle = inneighbor3i + markindex;
785 // output the front and back triangles
786 outelement3i[0] = vertexremap[element[0]];
787 outelement3i[1] = vertexremap[element[1]];
788 outelement3i[2] = vertexremap[element[2]];
789 outelement3i[3] = vertexremap[element[2]] + 1;
790 outelement3i[4] = vertexremap[element[1]] + 1;
791 outelement3i[5] = vertexremap[element[0]] + 1;
795 // output the sides (facing outward from this triangle)
796 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
798 remappedelement[0] = vertexremap[element[0]];
799 remappedelement[1] = vertexremap[element[1]];
800 outelement3i[0] = remappedelement[1];
801 outelement3i[1] = remappedelement[0];
802 outelement3i[2] = remappedelement[0] + 1;
803 outelement3i[3] = remappedelement[1];
804 outelement3i[4] = remappedelement[0] + 1;
805 outelement3i[5] = remappedelement[1] + 1;
810 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
812 remappedelement[1] = vertexremap[element[1]];
813 remappedelement[2] = vertexremap[element[2]];
814 outelement3i[0] = remappedelement[2];
815 outelement3i[1] = remappedelement[1];
816 outelement3i[2] = remappedelement[1] + 1;
817 outelement3i[3] = remappedelement[2];
818 outelement3i[4] = remappedelement[1] + 1;
819 outelement3i[5] = remappedelement[2] + 1;
824 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
826 remappedelement[0] = vertexremap[element[0]];
827 remappedelement[2] = vertexremap[element[2]];
828 outelement3i[0] = remappedelement[0];
829 outelement3i[1] = remappedelement[2];
830 outelement3i[2] = remappedelement[2] + 1;
831 outelement3i[3] = remappedelement[0];
832 outelement3i[4] = remappedelement[2] + 1;
833 outelement3i[5] = remappedelement[0] + 1;
840 *outnumvertices = outvertices;
844 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)
847 if (projectdistance < 0.1)
849 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
852 if (!numverts || !nummarktris)
854 // make sure shadowelements is big enough for this volume
855 if (maxshadowelements < nummarktris * 24)
856 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
857 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
858 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
861 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)
866 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
868 tend = firsttriangle + numtris;
869 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
870 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
871 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
873 // surface box entirely inside light box, no box cull
874 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
875 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
876 shadowmarklist[numshadowmark++] = t;
880 // surface box not entirely inside light box, cull each triangle
881 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
883 v[0] = invertex3f + e[0] * 3;
884 v[1] = invertex3f + e[1] * 3;
885 v[2] = invertex3f + e[2] * 3;
886 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
887 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
888 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
889 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
890 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
891 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
892 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
893 shadowmarklist[numshadowmark++] = t;
898 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
901 if (r_shadow_compilingrtlight)
903 // if we're compiling an rtlight, capture the mesh
904 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
907 memset(&m, 0, sizeof(m));
908 m.pointer_vertex = vertex3f;
910 GL_LockArrays(0, numvertices);
911 if (r_shadowstage == SHADOWSTAGE_STENCIL)
913 // increment stencil if backface is behind depthbuffer
914 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
915 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
916 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
918 c_rt_shadowtris += numtriangles;
919 // decrement stencil if frontface is behind depthbuffer
920 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
921 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
923 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
925 c_rt_shadowtris += numtriangles;
929 static void R_Shadow_MakeTextures(void)
931 int x, y, z, d, side;
932 float v[3], s, t, intensity;
934 R_FreeTexturePool(&r_shadow_texturepool);
935 r_shadow_texturepool = R_AllocTexturePool();
936 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
937 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
939 #define ATTEN2DSIZE 64
940 #define ATTEN3DSIZE 32
941 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
942 r_shadow_blankwhitecubetexture = NULL;
943 r_shadow_normalcubetexture = NULL;
944 if (gl_texturecubemap)
946 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
947 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
948 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
949 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
950 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
951 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
952 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
953 for (side = 0;side < 6;side++)
955 for (y = 0;y < NORMSIZE;y++)
957 for (x = 0;x < NORMSIZE;x++)
959 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
960 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
994 intensity = 127.0f / sqrt(DotProduct(v, v));
995 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
996 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
997 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
998 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1002 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1004 for (y = 0;y < ATTEN2DSIZE;y++)
1006 for (x = 0;x < ATTEN2DSIZE;x++)
1008 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1009 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1011 intensity = 1.0f - sqrt(DotProduct(v, v));
1013 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1014 d = bound(0, intensity, 255);
1015 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1016 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1017 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1018 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1021 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1022 if (r_shadow_texture3d.integer)
1024 for (z = 0;z < ATTEN3DSIZE;z++)
1026 for (y = 0;y < ATTEN3DSIZE;y++)
1028 for (x = 0;x < ATTEN3DSIZE;x++)
1030 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1031 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1032 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1033 intensity = 1.0f - sqrt(DotProduct(v, v));
1035 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1036 d = bound(0, intensity, 255);
1037 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1038 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1039 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1040 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1044 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1049 void R_Shadow_ValidateCvars(void)
1051 if (r_shadow_texture3d.integer && !gl_texture3d)
1052 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1053 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1054 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1057 void R_Shadow_Stage_Begin(void)
1061 R_Shadow_ValidateCvars();
1063 if (!r_shadow_attenuation2dtexture
1064 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1065 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1066 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1067 R_Shadow_MakeTextures();
1069 memset(&m, 0, sizeof(m));
1070 GL_BlendFunc(GL_ONE, GL_ZERO);
1071 GL_DepthMask(false);
1074 GL_Color(0, 0, 0, 1);
1075 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1076 qglEnable(GL_CULL_FACE);
1077 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1078 r_shadowstage = SHADOWSTAGE_NONE;
1081 void R_Shadow_Stage_ShadowVolumes(void)
1084 memset(&m, 0, sizeof(m));
1086 GL_Color(1, 1, 1, 1);
1087 GL_ColorMask(0, 0, 0, 0);
1088 GL_BlendFunc(GL_ONE, GL_ZERO);
1089 GL_DepthMask(false);
1091 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1092 //if (r_shadow_shadow_polygonoffset.value != 0)
1094 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1095 // qglEnable(GL_POLYGON_OFFSET_FILL);
1098 // qglDisable(GL_POLYGON_OFFSET_FILL);
1099 qglDepthFunc(GL_LESS);
1100 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1101 qglEnable(GL_STENCIL_TEST);
1102 qglStencilFunc(GL_ALWAYS, 128, ~0);
1103 if (gl_ext_stenciltwoside.integer)
1105 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1106 qglDisable(GL_CULL_FACE);
1107 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1108 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1110 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1111 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1113 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1117 r_shadowstage = SHADOWSTAGE_STENCIL;
1118 qglEnable(GL_CULL_FACE);
1120 // this is changed by every shadow render so its value here is unimportant
1121 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1123 GL_Clear(GL_STENCIL_BUFFER_BIT);
1125 // LordHavoc note: many shadow volumes reside entirely inside the world
1126 // (that is to say they are entirely bounded by their lit surfaces),
1127 // which can be optimized by handling things as an inverted light volume,
1128 // with the shadow boundaries of the world being simulated by an altered
1129 // (129) bias to stencil clearing on such lights
1130 // FIXME: generate inverted light volumes for use as shadow volumes and
1131 // optimize for them as noted above
1134 void R_Shadow_Stage_Light(int shadowtest)
1137 memset(&m, 0, sizeof(m));
1139 GL_BlendFunc(GL_ONE, GL_ONE);
1140 GL_DepthMask(false);
1142 qglPolygonOffset(0, 0);
1143 //qglDisable(GL_POLYGON_OFFSET_FILL);
1144 GL_Color(1, 1, 1, 1);
1145 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1146 qglDepthFunc(GL_EQUAL);
1147 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1148 qglEnable(GL_CULL_FACE);
1150 qglEnable(GL_STENCIL_TEST);
1152 qglDisable(GL_STENCIL_TEST);
1153 if (gl_support_stenciltwoside)
1154 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1156 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1157 // only draw light where this geometry was already rendered AND the
1158 // stencil is 128 (values other than this mean shadow)
1159 qglStencilFunc(GL_EQUAL, 128, ~0);
1160 r_shadowstage = SHADOWSTAGE_LIGHT;
1164 void R_Shadow_Stage_End(void)
1167 memset(&m, 0, sizeof(m));
1169 GL_BlendFunc(GL_ONE, GL_ZERO);
1172 qglPolygonOffset(0, 0);
1173 //qglDisable(GL_POLYGON_OFFSET_FILL);
1174 GL_Color(1, 1, 1, 1);
1175 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1176 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1177 qglDepthFunc(GL_LEQUAL);
1178 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1179 qglDisable(GL_STENCIL_TEST);
1180 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1181 if (gl_support_stenciltwoside)
1182 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1184 qglStencilFunc(GL_ALWAYS, 128, ~0);
1185 r_shadowstage = SHADOWSTAGE_NONE;
1188 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1190 int i, ix1, iy1, ix2, iy2;
1191 float x1, y1, x2, y2, x, y, f;
1192 vec3_t smins, smaxs;
1194 if (!r_shadow_scissor.integer)
1196 // if view is inside the box, just say yes it's visible
1197 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1199 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1202 for (i = 0;i < 3;i++)
1204 if (r_viewforward[i] >= 0)
1215 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1216 if (DotProduct(r_viewforward, v2) <= f)
1218 // entirely behind nearclip plane
1221 if (DotProduct(r_viewforward, v) >= f)
1223 // entirely infront of nearclip plane
1224 x1 = y1 = x2 = y2 = 0;
1225 for (i = 0;i < 8;i++)
1227 v[0] = (i & 1) ? mins[0] : maxs[0];
1228 v[1] = (i & 2) ? mins[1] : maxs[1];
1229 v[2] = (i & 4) ? mins[2] : maxs[2];
1231 GL_TransformToScreen(v, v2);
1232 //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]);
1251 // clipped by nearclip plane
1252 // this is nasty and crude...
1253 // create viewspace bbox
1254 for (i = 0;i < 8;i++)
1256 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1257 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1258 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1259 v2[0] = -DotProduct(v, r_viewleft);
1260 v2[1] = DotProduct(v, r_viewup);
1261 v2[2] = DotProduct(v, r_viewforward);
1264 if (smins[0] > v2[0]) smins[0] = v2[0];
1265 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1266 if (smins[1] > v2[1]) smins[1] = v2[1];
1267 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1268 if (smins[2] > v2[2]) smins[2] = v2[2];
1269 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1273 smins[0] = smaxs[0] = v2[0];
1274 smins[1] = smaxs[1] = v2[1];
1275 smins[2] = smaxs[2] = v2[2];
1278 // now we have a bbox in viewspace
1279 // clip it to the view plane
1282 // return true if that culled the box
1283 if (smins[2] >= smaxs[2])
1285 // ok some of it is infront of the view, transform each corner back to
1286 // worldspace and then to screenspace and make screen rect
1287 // initialize these variables just to avoid compiler warnings
1288 x1 = y1 = x2 = y2 = 0;
1289 for (i = 0;i < 8;i++)
1291 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1292 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1293 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1294 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1295 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1296 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1298 GL_TransformToScreen(v, v2);
1299 //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]);
1316 // this code doesn't handle boxes with any points behind view properly
1317 x1 = 1000;x2 = -1000;
1318 y1 = 1000;y2 = -1000;
1319 for (i = 0;i < 8;i++)
1321 v[0] = (i & 1) ? mins[0] : maxs[0];
1322 v[1] = (i & 2) ? mins[1] : maxs[1];
1323 v[2] = (i & 4) ? mins[2] : maxs[2];
1325 GL_TransformToScreen(v, v2);
1326 //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]);
1344 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1345 if (ix1 < r_view_x) ix1 = r_view_x;
1346 if (iy1 < r_view_y) iy1 = r_view_y;
1347 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1348 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1349 if (ix2 <= ix1 || iy2 <= iy1)
1351 // set up the scissor rectangle
1352 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1353 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1354 //qglEnable(GL_SCISSOR_TEST);
1359 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1361 float *color4f = varray_color4f;
1362 float dist, dot, intensity, v[3], n[3];
1363 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1365 Matrix4x4_Transform(m, vertex3f, v);
1366 if ((dist = DotProduct(v, v)) < 1)
1368 Matrix4x4_Transform3x3(m, normal3f, n);
1369 if ((dot = DotProduct(n, v)) > 0)
1372 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1373 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1374 VectorScale(lightcolor, intensity, color4f);
1379 VectorClear(color4f);
1385 VectorClear(color4f);
1391 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1393 float *color4f = varray_color4f;
1394 float dist, dot, intensity, v[3], n[3];
1395 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1397 Matrix4x4_Transform(m, vertex3f, v);
1398 if ((dist = fabs(v[2])) < 1)
1400 Matrix4x4_Transform3x3(m, normal3f, n);
1401 if ((dot = DotProduct(n, v)) > 0)
1403 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1404 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1405 VectorScale(lightcolor, intensity, color4f);
1410 VectorClear(color4f);
1416 VectorClear(color4f);
1422 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1424 float *color4f = varray_color4f;
1425 float dot, intensity, v[3], n[3];
1426 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1428 Matrix4x4_Transform(m, vertex3f, v);
1429 Matrix4x4_Transform3x3(m, normal3f, n);
1430 if ((dot = DotProduct(n, v)) > 0)
1432 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1433 VectorScale(lightcolor, intensity, color4f);
1438 VectorClear(color4f);
1444 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1446 float *color4f = varray_color4f;
1447 float dist, intensity, v[3];
1448 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1450 Matrix4x4_Transform(m, vertex3f, v);
1451 if ((dist = DotProduct(v, v)) < 1)
1454 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1455 VectorScale(lightcolor, intensity, color4f);
1460 VectorClear(color4f);
1466 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1468 float *color4f = varray_color4f;
1469 float dist, intensity, v[3];
1470 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1472 Matrix4x4_Transform(m, vertex3f, v);
1473 if ((dist = fabs(v[2])) < 1)
1475 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1476 VectorScale(lightcolor, intensity, color4f);
1481 VectorClear(color4f);
1487 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1488 #define USETEXMATRIX
1490 #ifndef USETEXMATRIX
1491 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1492 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1493 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1497 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1498 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1499 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1506 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1510 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1511 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1519 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)
1523 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1525 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1526 // the cubemap normalizes this for us
1527 out3f[0] = DotProduct(svector3f, lightdir);
1528 out3f[1] = DotProduct(tvector3f, lightdir);
1529 out3f[2] = DotProduct(normal3f, lightdir);
1533 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)
1536 float lightdir[3], eyedir[3], halfdir[3];
1537 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1539 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1540 VectorNormalizeFast(lightdir);
1541 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1542 VectorNormalizeFast(eyedir);
1543 VectorAdd(lightdir, eyedir, halfdir);
1544 // the cubemap normalizes this for us
1545 out3f[0] = DotProduct(svector3f, halfdir);
1546 out3f[1] = DotProduct(tvector3f, halfdir);
1547 out3f[2] = DotProduct(normal3f, halfdir);
1551 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
1554 float color[3], color2[3], colorscale;
1557 basetexture = r_texture_white;
1559 bumptexture = r_texture_blanknormalmap;
1560 if (!lightcolorbase)
1561 lightcolorbase = vec3_origin;
1562 if (!lightcolorpants)
1563 lightcolorpants = vec3_origin;
1564 if (!lightcolorshirt)
1565 lightcolorshirt = vec3_origin;
1566 specularscale *= r_shadow_glossintensity.value;
1569 if (r_shadow_gloss.integer >= 2)
1571 glosstexture = r_texture_white;
1572 specularscale *= r_shadow_gloss2intensity.value;
1576 glosstexture = r_texture_black;
1580 if (r_shadow_gloss.integer < 1)
1583 lightcubemap = r_shadow_blankwhitecubetexture;
1584 if ((ambientscale + diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1586 // FIXME: support EF_NODEPTHTEST
1587 GL_DepthMask(false);
1589 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1591 unsigned int perm, prog;
1592 // GLSL shader path (GFFX5200, Radeon 9500)
1593 memset(&m, 0, sizeof(m));
1594 m.pointer_vertex = vertex3f;
1595 m.pointer_texcoord[0] = texcoord2f;
1596 m.pointer_texcoord3f[1] = svector3f;
1597 m.pointer_texcoord3f[2] = tvector3f;
1598 m.pointer_texcoord3f[3] = normal3f;
1599 m.tex[0] = R_GetTexture(bumptexture);
1600 m.tex[1] = R_GetTexture(basetexture);
1601 m.tex[2] = R_GetTexture(glosstexture);
1602 m.texcubemap[3] = R_GetTexture(lightcubemap);
1603 // TODO: support fog (after renderer is converted to texture fog)
1604 m.tex[4] = R_GetTexture(r_texture_white);
1605 m.texmatrix[3] = *matrix_modeltolight;
1607 GL_BlendFunc(GL_ONE, GL_ONE);
1608 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1611 // only add a feature to the permutation if that permutation exists
1612 // (otherwise it might end up not using a shader at all, which looks
1613 // worse than using less features)
1614 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1615 perm |= SHADERPERMUTATION_SPECULAR;
1616 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1617 // perm |= SHADERPERMUTATION_FOG;
1618 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1619 perm |= SHADERPERMUTATION_CUBEFILTER;
1620 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1621 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1622 prog = r_shadow_program_light[perm];
1623 qglUseProgramObjectARB(prog);CHECKGLERROR
1624 // TODO: support fog (after renderer is converted to texture fog)
1625 if (perm & SHADERPERMUTATION_FOG)
1627 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1629 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1630 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1631 if (perm & SHADERPERMUTATION_SPECULAR)
1633 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1634 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1636 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1637 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1638 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1640 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1642 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1644 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1645 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1648 GL_LockArrays(firstvertex, numvertices);
1649 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1651 c_rt_lighttris += numtriangles;
1652 // TODO: add direct pants/shirt rendering
1653 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1655 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1656 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1657 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1659 c_rt_lighttris += numtriangles;
1661 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1663 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1664 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1665 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1667 c_rt_lighttris += numtriangles;
1669 GL_LockArrays(0, 0);
1670 qglUseProgramObjectARB(0);
1671 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1672 qglBegin(GL_TRIANGLES);
1676 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1678 // TODO: add direct pants/shirt rendering
1679 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1680 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale);
1681 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1682 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale);
1684 bumptexture = r_texture_blanknormalmap;
1686 glosstexture = r_texture_white;
1690 colorscale = ambientscale;
1691 // colorscale accounts for how much we multiply the brightness
1694 // mult is how many times the final pass of the lighting will be
1695 // performed to get more brightness than otherwise possible.
1697 // Limit mult to 64 for sanity sake.
1698 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1700 // 3 3D combine path (Geforce3, Radeon 8500)
1701 memset(&m, 0, sizeof(m));
1702 m.pointer_vertex = vertex3f;
1703 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1705 m.pointer_texcoord3f[0] = vertex3f;
1706 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1708 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1709 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1711 m.tex[1] = R_GetTexture(basetexture);
1712 m.pointer_texcoord[1] = texcoord2f;
1713 m.texcubemap[2] = R_GetTexture(lightcubemap);
1715 m.pointer_texcoord3f[2] = vertex3f;
1716 m.texmatrix[2] = *matrix_modeltolight;
1718 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1719 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1721 GL_BlendFunc(GL_ONE, GL_ONE);
1723 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1725 // 2 3D combine path (Geforce3, original Radeon)
1726 memset(&m, 0, sizeof(m));
1727 m.pointer_vertex = vertex3f;
1728 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1730 m.pointer_texcoord3f[0] = vertex3f;
1731 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1733 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1734 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1736 m.tex[1] = R_GetTexture(basetexture);
1737 m.pointer_texcoord[1] = texcoord2f;
1738 GL_BlendFunc(GL_ONE, GL_ONE);
1740 else if (r_textureunits.integer >= 4 && lightcubemap)
1742 // 4 2D combine path (Geforce3, Radeon 8500)
1743 memset(&m, 0, sizeof(m));
1744 m.pointer_vertex = vertex3f;
1745 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1747 m.pointer_texcoord3f[0] = vertex3f;
1748 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1750 m.pointer_texcoord[0] = varray_texcoord2f[0];
1751 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1753 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1755 m.pointer_texcoord3f[1] = vertex3f;
1756 m.texmatrix[1] = *matrix_modeltoattenuationz;
1758 m.pointer_texcoord[1] = varray_texcoord2f[1];
1759 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1761 m.tex[2] = R_GetTexture(basetexture);
1762 m.pointer_texcoord[2] = texcoord2f;
1765 m.texcubemap[3] = R_GetTexture(lightcubemap);
1767 m.pointer_texcoord3f[3] = vertex3f;
1768 m.texmatrix[3] = *matrix_modeltolight;
1770 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1771 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1774 GL_BlendFunc(GL_ONE, GL_ONE);
1776 else if (r_textureunits.integer >= 3 && !lightcubemap)
1778 // 3 2D combine path (Geforce3, original Radeon)
1779 memset(&m, 0, sizeof(m));
1780 m.pointer_vertex = vertex3f;
1781 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1783 m.pointer_texcoord3f[0] = vertex3f;
1784 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1786 m.pointer_texcoord[0] = varray_texcoord2f[0];
1787 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1789 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1791 m.pointer_texcoord3f[1] = vertex3f;
1792 m.texmatrix[1] = *matrix_modeltoattenuationz;
1794 m.pointer_texcoord[1] = varray_texcoord2f[1];
1795 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1797 m.tex[2] = R_GetTexture(basetexture);
1798 m.pointer_texcoord[2] = texcoord2f;
1799 GL_BlendFunc(GL_ONE, GL_ONE);
1803 // 2/2/2 2D combine path (any dot3 card)
1804 memset(&m, 0, sizeof(m));
1805 m.pointer_vertex = vertex3f;
1806 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1808 m.pointer_texcoord3f[0] = vertex3f;
1809 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1811 m.pointer_texcoord[0] = varray_texcoord2f[0];
1812 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1814 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1816 m.pointer_texcoord3f[1] = vertex3f;
1817 m.texmatrix[1] = *matrix_modeltoattenuationz;
1819 m.pointer_texcoord[1] = varray_texcoord2f[1];
1820 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1823 GL_ColorMask(0,0,0,1);
1824 GL_BlendFunc(GL_ONE, GL_ZERO);
1825 GL_LockArrays(firstvertex, numvertices);
1826 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1827 GL_LockArrays(0, 0);
1829 c_rt_lighttris += numtriangles;
1831 memset(&m, 0, sizeof(m));
1832 m.pointer_vertex = vertex3f;
1833 m.tex[0] = R_GetTexture(basetexture);
1834 m.pointer_texcoord[0] = texcoord2f;
1837 m.texcubemap[1] = R_GetTexture(lightcubemap);
1839 m.pointer_texcoord3f[1] = vertex3f;
1840 m.texmatrix[1] = *matrix_modeltolight;
1842 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1843 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1846 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1848 // this final code is shared
1850 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1851 VectorScale(lightcolorbase, colorscale, color2);
1852 GL_LockArrays(firstvertex, numvertices);
1853 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1855 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1856 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1858 c_rt_lighttris += numtriangles;
1860 GL_LockArrays(0, 0);
1865 colorscale = diffusescale;
1866 // colorscale accounts for how much we multiply the brightness
1869 // mult is how many times the final pass of the lighting will be
1870 // performed to get more brightness than otherwise possible.
1872 // Limit mult to 64 for sanity sake.
1873 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1875 // 3/2 3D combine path (Geforce3, Radeon 8500)
1876 memset(&m, 0, sizeof(m));
1877 m.pointer_vertex = vertex3f;
1878 m.tex[0] = R_GetTexture(bumptexture);
1879 m.texcombinergb[0] = GL_REPLACE;
1880 m.pointer_texcoord[0] = texcoord2f;
1881 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1882 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1883 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1884 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1885 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1887 m.pointer_texcoord3f[2] = vertex3f;
1888 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1890 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1891 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1894 GL_ColorMask(0,0,0,1);
1895 GL_BlendFunc(GL_ONE, GL_ZERO);
1896 GL_LockArrays(firstvertex, numvertices);
1897 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1898 GL_LockArrays(0, 0);
1900 c_rt_lighttris += numtriangles;
1902 memset(&m, 0, sizeof(m));
1903 m.pointer_vertex = vertex3f;
1904 m.tex[0] = R_GetTexture(basetexture);
1905 m.pointer_texcoord[0] = texcoord2f;
1908 m.texcubemap[1] = R_GetTexture(lightcubemap);
1910 m.pointer_texcoord3f[1] = vertex3f;
1911 m.texmatrix[1] = *matrix_modeltolight;
1913 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1914 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1917 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1919 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1921 // 1/2/2 3D combine path (original Radeon)
1922 memset(&m, 0, sizeof(m));
1923 m.pointer_vertex = vertex3f;
1924 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1926 m.pointer_texcoord3f[0] = vertex3f;
1927 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1929 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1930 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1933 GL_ColorMask(0,0,0,1);
1934 GL_BlendFunc(GL_ONE, GL_ZERO);
1935 GL_LockArrays(firstvertex, numvertices);
1936 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1937 GL_LockArrays(0, 0);
1939 c_rt_lighttris += numtriangles;
1941 memset(&m, 0, sizeof(m));
1942 m.pointer_vertex = vertex3f;
1943 m.tex[0] = R_GetTexture(bumptexture);
1944 m.texcombinergb[0] = GL_REPLACE;
1945 m.pointer_texcoord[0] = texcoord2f;
1946 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1947 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1948 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1949 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1951 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1952 GL_LockArrays(firstvertex, numvertices);
1953 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1954 GL_LockArrays(0, 0);
1956 c_rt_lighttris += numtriangles;
1958 memset(&m, 0, sizeof(m));
1959 m.pointer_vertex = vertex3f;
1960 m.tex[0] = R_GetTexture(basetexture);
1961 m.pointer_texcoord[0] = texcoord2f;
1964 m.texcubemap[1] = R_GetTexture(lightcubemap);
1966 m.pointer_texcoord3f[1] = vertex3f;
1967 m.texmatrix[1] = *matrix_modeltolight;
1969 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1970 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1973 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1975 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1977 // 2/2 3D combine path (original Radeon)
1978 memset(&m, 0, sizeof(m));
1979 m.pointer_vertex = vertex3f;
1980 m.tex[0] = R_GetTexture(bumptexture);
1981 m.texcombinergb[0] = GL_REPLACE;
1982 m.pointer_texcoord[0] = texcoord2f;
1983 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1984 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1985 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1986 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1988 GL_ColorMask(0,0,0,1);
1989 GL_BlendFunc(GL_ONE, GL_ZERO);
1990 GL_LockArrays(firstvertex, numvertices);
1991 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1992 GL_LockArrays(0, 0);
1994 c_rt_lighttris += numtriangles;
1996 memset(&m, 0, sizeof(m));
1997 m.pointer_vertex = vertex3f;
1998 m.tex[0] = R_GetTexture(basetexture);
1999 m.pointer_texcoord[0] = texcoord2f;
2000 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2002 m.pointer_texcoord3f[1] = vertex3f;
2003 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2005 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2006 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2008 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2010 else if (r_textureunits.integer >= 4)
2012 // 4/2 2D combine path (Geforce3, Radeon 8500)
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_shadow_normalcubetexture);
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, relativelightorigin);
2022 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2024 m.pointer_texcoord3f[2] = vertex3f;
2025 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2027 m.pointer_texcoord[2] = varray_texcoord2f[2];
2028 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2030 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2032 m.pointer_texcoord3f[3] = vertex3f;
2033 m.texmatrix[3] = *matrix_modeltoattenuationz;
2035 m.pointer_texcoord[3] = varray_texcoord2f[3];
2036 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2039 GL_ColorMask(0,0,0,1);
2040 GL_BlendFunc(GL_ONE, GL_ZERO);
2041 GL_LockArrays(firstvertex, numvertices);
2042 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2043 GL_LockArrays(0, 0);
2045 c_rt_lighttris += numtriangles;
2047 memset(&m, 0, sizeof(m));
2048 m.pointer_vertex = vertex3f;
2049 m.tex[0] = R_GetTexture(basetexture);
2050 m.pointer_texcoord[0] = texcoord2f;
2053 m.texcubemap[1] = R_GetTexture(lightcubemap);
2055 m.pointer_texcoord3f[1] = vertex3f;
2056 m.texmatrix[1] = *matrix_modeltolight;
2058 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2059 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2062 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2066 // 2/2/2 2D combine path (any dot3 card)
2067 memset(&m, 0, sizeof(m));
2068 m.pointer_vertex = vertex3f;
2069 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2071 m.pointer_texcoord3f[0] = vertex3f;
2072 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2074 m.pointer_texcoord[0] = varray_texcoord2f[0];
2075 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2077 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2079 m.pointer_texcoord3f[1] = vertex3f;
2080 m.texmatrix[1] = *matrix_modeltoattenuationz;
2082 m.pointer_texcoord[1] = varray_texcoord2f[1];
2083 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2086 GL_ColorMask(0,0,0,1);
2087 GL_BlendFunc(GL_ONE, GL_ZERO);
2088 GL_LockArrays(firstvertex, numvertices);
2089 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2090 GL_LockArrays(0, 0);
2092 c_rt_lighttris += numtriangles;
2094 memset(&m, 0, sizeof(m));
2095 m.pointer_vertex = vertex3f;
2096 m.tex[0] = R_GetTexture(bumptexture);
2097 m.texcombinergb[0] = GL_REPLACE;
2098 m.pointer_texcoord[0] = texcoord2f;
2099 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2100 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2101 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2102 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2104 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2105 GL_LockArrays(firstvertex, numvertices);
2106 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2107 GL_LockArrays(0, 0);
2109 c_rt_lighttris += numtriangles;
2111 memset(&m, 0, sizeof(m));
2112 m.pointer_vertex = vertex3f;
2113 m.tex[0] = R_GetTexture(basetexture);
2114 m.pointer_texcoord[0] = texcoord2f;
2117 m.texcubemap[1] = R_GetTexture(lightcubemap);
2119 m.pointer_texcoord3f[1] = vertex3f;
2120 m.texmatrix[1] = *matrix_modeltolight;
2122 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2123 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2126 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2128 // this final code is shared
2130 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2131 VectorScale(lightcolorbase, colorscale, color2);
2132 GL_LockArrays(firstvertex, numvertices);
2133 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2135 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2136 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2138 c_rt_lighttris += numtriangles;
2140 GL_LockArrays(0, 0);
2142 if (specularscale && glosstexture != r_texture_black)
2144 // FIXME: detect blendsquare!
2145 //if (gl_support_blendsquare)
2147 colorscale = specularscale;
2149 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2151 // 2/0/0/1/2 3D combine blendsquare path
2152 memset(&m, 0, sizeof(m));
2153 m.pointer_vertex = vertex3f;
2154 m.tex[0] = R_GetTexture(bumptexture);
2155 m.pointer_texcoord[0] = texcoord2f;
2156 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2157 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2158 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2159 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2161 GL_ColorMask(0,0,0,1);
2162 // this squares the result
2163 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2164 GL_LockArrays(firstvertex, numvertices);
2165 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2166 GL_LockArrays(0, 0);
2168 c_rt_lighttris += numtriangles;
2170 memset(&m, 0, sizeof(m));
2171 m.pointer_vertex = vertex3f;
2173 GL_LockArrays(firstvertex, numvertices);
2174 // square alpha in framebuffer a few times to make it shiny
2175 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2176 // these comments are a test run through this math for intensity 0.5
2177 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2178 // 0.25 * 0.25 = 0.0625 (this is another pass)
2179 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2180 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2182 c_rt_lighttris += numtriangles;
2183 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2185 c_rt_lighttris += numtriangles;
2186 GL_LockArrays(0, 0);
2188 memset(&m, 0, sizeof(m));
2189 m.pointer_vertex = vertex3f;
2190 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2192 m.pointer_texcoord3f[0] = vertex3f;
2193 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2195 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2196 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2199 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2200 GL_LockArrays(firstvertex, numvertices);
2201 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2202 GL_LockArrays(0, 0);
2204 c_rt_lighttris += numtriangles;
2206 memset(&m, 0, sizeof(m));
2207 m.pointer_vertex = vertex3f;
2208 m.tex[0] = R_GetTexture(glosstexture);
2209 m.pointer_texcoord[0] = texcoord2f;
2212 m.texcubemap[1] = R_GetTexture(lightcubemap);
2214 m.pointer_texcoord3f[1] = vertex3f;
2215 m.texmatrix[1] = *matrix_modeltolight;
2217 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2218 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2221 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2223 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2225 // 2/0/0/2 3D combine blendsquare path
2226 memset(&m, 0, sizeof(m));
2227 m.pointer_vertex = vertex3f;
2228 m.tex[0] = R_GetTexture(bumptexture);
2229 m.pointer_texcoord[0] = texcoord2f;
2230 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2231 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2232 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2233 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2235 GL_ColorMask(0,0,0,1);
2236 // this squares the result
2237 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2238 GL_LockArrays(firstvertex, numvertices);
2239 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2240 GL_LockArrays(0, 0);
2242 c_rt_lighttris += numtriangles;
2244 memset(&m, 0, sizeof(m));
2245 m.pointer_vertex = vertex3f;
2247 GL_LockArrays(firstvertex, numvertices);
2248 // square alpha in framebuffer a few times to make it shiny
2249 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2250 // these comments are a test run through this math for intensity 0.5
2251 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2252 // 0.25 * 0.25 = 0.0625 (this is another pass)
2253 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2254 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2256 c_rt_lighttris += numtriangles;
2257 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2259 c_rt_lighttris += numtriangles;
2260 GL_LockArrays(0, 0);
2262 memset(&m, 0, sizeof(m));
2263 m.pointer_vertex = vertex3f;
2264 m.tex[0] = R_GetTexture(glosstexture);
2265 m.pointer_texcoord[0] = texcoord2f;
2266 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2268 m.pointer_texcoord3f[1] = vertex3f;
2269 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2271 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2272 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2274 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2278 // 2/0/0/2/2 2D combine blendsquare path
2279 memset(&m, 0, sizeof(m));
2280 m.pointer_vertex = vertex3f;
2281 m.tex[0] = R_GetTexture(bumptexture);
2282 m.pointer_texcoord[0] = texcoord2f;
2283 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2284 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2285 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2286 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2288 GL_ColorMask(0,0,0,1);
2289 // this squares the result
2290 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2291 GL_LockArrays(firstvertex, numvertices);
2292 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2293 GL_LockArrays(0, 0);
2295 c_rt_lighttris += numtriangles;
2297 memset(&m, 0, sizeof(m));
2298 m.pointer_vertex = vertex3f;
2300 GL_LockArrays(firstvertex, numvertices);
2301 // square alpha in framebuffer a few times to make it shiny
2302 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2303 // these comments are a test run through this math for intensity 0.5
2304 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2305 // 0.25 * 0.25 = 0.0625 (this is another pass)
2306 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2307 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2309 c_rt_lighttris += numtriangles;
2310 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2312 c_rt_lighttris += numtriangles;
2313 GL_LockArrays(0, 0);
2315 memset(&m, 0, sizeof(m));
2316 m.pointer_vertex = vertex3f;
2317 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2319 m.pointer_texcoord3f[0] = vertex3f;
2320 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2322 m.pointer_texcoord[0] = varray_texcoord2f[0];
2323 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2325 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2327 m.pointer_texcoord3f[1] = vertex3f;
2328 m.texmatrix[1] = *matrix_modeltoattenuationz;
2330 m.pointer_texcoord[1] = varray_texcoord2f[1];
2331 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2334 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2335 GL_LockArrays(firstvertex, numvertices);
2336 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2337 GL_LockArrays(0, 0);
2339 c_rt_lighttris += numtriangles;
2341 memset(&m, 0, sizeof(m));
2342 m.pointer_vertex = vertex3f;
2343 m.tex[0] = R_GetTexture(glosstexture);
2344 m.pointer_texcoord[0] = texcoord2f;
2347 m.texcubemap[1] = R_GetTexture(lightcubemap);
2349 m.pointer_texcoord3f[1] = vertex3f;
2350 m.texmatrix[1] = *matrix_modeltolight;
2352 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2353 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2356 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2359 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2360 VectorScale(lightcolorbase, colorscale, color2);
2361 GL_LockArrays(firstvertex, numvertices);
2362 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2364 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2365 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2367 c_rt_lighttris += numtriangles;
2369 GL_LockArrays(0, 0);
2375 // TODO: add direct pants/shirt rendering
2376 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2377 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale);
2378 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2379 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale);
2382 GL_BlendFunc(GL_ONE, GL_ONE);
2383 VectorScale(lightcolorbase, ambientscale, color2);
2384 memset(&m, 0, sizeof(m));
2385 m.pointer_vertex = vertex3f;
2386 m.tex[0] = R_GetTexture(basetexture);
2387 m.pointer_texcoord[0] = texcoord2f;
2388 if (r_textureunits.integer >= 2)
2391 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2393 m.pointer_texcoord3f[1] = vertex3f;
2394 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2396 m.pointer_texcoord[1] = varray_texcoord2f[1];
2397 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2399 if (r_textureunits.integer >= 3)
2401 // Geforce3/Radeon class but not using dot3
2402 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2404 m.pointer_texcoord3f[2] = vertex3f;
2405 m.texmatrix[2] = *matrix_modeltoattenuationz;
2407 m.pointer_texcoord[2] = varray_texcoord2f[2];
2408 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2412 if (r_textureunits.integer >= 3)
2413 m.pointer_color = NULL;
2415 m.pointer_color = varray_color4f;
2417 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2419 color[0] = bound(0, color2[0], 1);
2420 color[1] = bound(0, color2[1], 1);
2421 color[2] = bound(0, color2[2], 1);
2422 if (r_textureunits.integer >= 3)
2423 GL_Color(color[0], color[1], color[2], 1);
2424 else if (r_textureunits.integer >= 2)
2425 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2427 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2428 GL_LockArrays(firstvertex, numvertices);
2429 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2430 GL_LockArrays(0, 0);
2432 c_rt_lighttris += numtriangles;
2437 GL_BlendFunc(GL_ONE, GL_ONE);
2438 VectorScale(lightcolorbase, diffusescale, color2);
2439 memset(&m, 0, sizeof(m));
2440 m.pointer_vertex = vertex3f;
2441 m.pointer_color = varray_color4f;
2442 m.tex[0] = R_GetTexture(basetexture);
2443 m.pointer_texcoord[0] = texcoord2f;
2444 if (r_textureunits.integer >= 2)
2447 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2449 m.pointer_texcoord3f[1] = vertex3f;
2450 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2452 m.pointer_texcoord[1] = varray_texcoord2f[1];
2453 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2455 if (r_textureunits.integer >= 3)
2457 // Geforce3/Radeon class but not using dot3
2458 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2460 m.pointer_texcoord3f[2] = vertex3f;
2461 m.texmatrix[2] = *matrix_modeltoattenuationz;
2463 m.pointer_texcoord[2] = varray_texcoord2f[2];
2464 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2469 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2471 color[0] = bound(0, color2[0], 1);
2472 color[1] = bound(0, color2[1], 1);
2473 color[2] = bound(0, color2[2], 1);
2474 if (r_textureunits.integer >= 3)
2475 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2476 else if (r_textureunits.integer >= 2)
2477 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2479 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2480 GL_LockArrays(firstvertex, numvertices);
2481 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2482 GL_LockArrays(0, 0);
2484 c_rt_lighttris += numtriangles;
2490 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2494 R_RTLight_Uncompile(rtlight);
2495 memset(rtlight, 0, sizeof(*rtlight));
2497 VectorCopy(light->origin, rtlight->shadoworigin);
2498 VectorCopy(light->color, rtlight->color);
2499 rtlight->radius = light->radius;
2500 //rtlight->cullradius = rtlight->radius;
2501 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2502 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2503 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2504 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2505 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2506 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2507 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2508 rtlight->cubemapname[0] = 0;
2509 if (light->cubemapname[0])
2510 strcpy(rtlight->cubemapname, light->cubemapname);
2511 else if (light->cubemapnum > 0)
2512 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2513 rtlight->shadow = light->shadow;
2514 rtlight->corona = light->corona;
2515 rtlight->style = light->style;
2516 rtlight->isstatic = isstatic;
2517 rtlight->coronasizescale = light->coronasizescale;
2518 rtlight->ambientscale = light->ambientscale;
2519 rtlight->diffusescale = light->diffusescale;
2520 rtlight->specularscale = light->specularscale;
2521 rtlight->flags = light->flags;
2522 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2523 // ConcatScale won't work here because this needs to scale rotate and
2524 // translate, not just rotate
2525 scale = 1.0f / rtlight->radius;
2526 for (k = 0;k < 3;k++)
2527 for (j = 0;j < 4;j++)
2528 rtlight->matrix_worldtolight.m[k][j] *= scale;
2529 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2530 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2532 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2533 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2534 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2535 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2538 // compiles rtlight geometry
2539 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2540 void R_RTLight_Compile(rtlight_t *rtlight)
2542 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2543 entity_render_t *ent = r_refdef.worldentity;
2544 model_t *model = r_refdef.worldmodel;
2546 // compile the light
2547 rtlight->compiled = true;
2548 rtlight->static_numclusters = 0;
2549 rtlight->static_numclusterpvsbytes = 0;
2550 rtlight->static_clusterlist = NULL;
2551 rtlight->static_clusterpvs = NULL;
2552 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2553 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2554 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2555 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2556 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2557 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2559 if (model && model->GetLightInfo)
2561 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2562 r_shadow_compilingrtlight = rtlight;
2563 R_Shadow_EnlargeClusterSurfaceBuffer(model->brush.num_pvsclusters, model->nummodelsurfaces);
2564 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2565 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2566 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2569 rtlight->static_numclusters = numclusters;
2570 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2571 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2572 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2574 if (model->DrawShadowVolume && rtlight->shadow)
2576 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2577 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2578 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2580 if (model->DrawLight)
2582 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2583 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, 0, 0, 0, numsurfaces, r_shadow_buffer_surfacelist);
2584 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2586 // switch back to rendering when DrawShadowVolume or DrawLight is called
2587 r_shadow_compilingrtlight = NULL;
2591 // use smallest available cullradius - box radius or light radius
2592 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2593 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2597 if (rtlight->static_meshchain_shadow)
2600 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2603 shadowtris += mesh->numtriangles;
2609 if (rtlight->static_meshchain_light)
2612 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2615 lighttris += mesh->numtriangles;
2619 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);
2622 void R_RTLight_Uncompile(rtlight_t *rtlight)
2624 if (rtlight->compiled)
2626 if (rtlight->static_meshchain_shadow)
2627 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2628 rtlight->static_meshchain_shadow = NULL;
2629 if (rtlight->static_meshchain_light)
2630 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2631 rtlight->static_meshchain_light = NULL;
2632 if (rtlight->static_clusterlist)
2633 Mem_Free(rtlight->static_clusterlist);
2634 rtlight->static_clusterlist = NULL;
2635 if (rtlight->static_clusterpvs)
2636 Mem_Free(rtlight->static_clusterpvs);
2637 rtlight->static_clusterpvs = NULL;
2638 rtlight->static_numclusters = 0;
2639 rtlight->static_numclusterpvsbytes = 0;
2640 rtlight->compiled = false;
2644 void R_Shadow_UncompileWorldLights(void)
2647 for (light = r_shadow_worldlightchain;light;light = light->next)
2648 R_RTLight_Uncompile(&light->rtlight);
2651 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2653 int i, shadow, usestencil;
2654 entity_render_t *ent;
2656 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2657 rtexture_t *cubemaptexture;
2658 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2659 int numclusters, numsurfaces;
2660 int *clusterlist, *surfacelist;
2662 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2666 // skip lights that don't light (corona only lights)
2667 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2670 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2671 VectorScale(rtlight->color, f, lightcolor);
2672 if (VectorLength2(lightcolor) < 0.01)
2675 if (rtlight->selected)
2677 f = 2 + sin(realtime * M_PI * 4.0);
2678 VectorScale(lightcolor, f, lightcolor);
2682 // loading is done before visibility checks because loading should happen
2683 // all at once at the start of a level, not when it stalls gameplay.
2684 // (especially important to benchmarks)
2685 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2686 R_RTLight_Compile(rtlight);
2687 if (rtlight->cubemapname[0])
2688 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2690 cubemaptexture = NULL;
2692 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2693 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2694 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2695 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2696 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2697 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2698 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2705 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2707 // compiled light, world available and can receive realtime lighting
2708 // retrieve cluster information
2709 numclusters = rtlight->static_numclusters;
2710 clusterlist = rtlight->static_clusterlist;
2711 clusterpvs = rtlight->static_clusterpvs;
2712 VectorCopy(rtlight->cullmins, cullmins);
2713 VectorCopy(rtlight->cullmaxs, cullmaxs);
2715 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2717 // dynamic light, world available and can receive realtime lighting
2718 // if the light box is offscreen, skip it right away
2719 if (R_CullBox(cullmins, cullmaxs))
2721 // calculate lit surfaces and clusters
2722 R_Shadow_EnlargeClusterSurfaceBuffer(r_refdef.worldmodel->brush.num_pvsclusters, r_refdef.worldmodel->nummodelsurfaces);
2723 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2724 clusterlist = r_shadow_buffer_clusterlist;
2725 clusterpvs = r_shadow_buffer_clusterpvs;
2726 surfacelist = r_shadow_buffer_surfacelist;
2728 // if the reduced cluster bounds are offscreen, skip it
2729 if (R_CullBox(cullmins, cullmaxs))
2731 // check if light is illuminating any visible clusters
2734 for (i = 0;i < numclusters;i++)
2735 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2737 if (i == numclusters)
2740 // set up a scissor rectangle for this light
2741 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2744 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2747 if (shadow && (gl_stencil || visiblevolumes))
2749 if (!visiblevolumes)
2751 R_Shadow_Stage_ShadowVolumes();
2754 ent = r_refdef.worldentity;
2755 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2757 memset(&m, 0, sizeof(m));
2758 R_Mesh_Matrix(&ent->matrix);
2759 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2761 m.pointer_vertex = mesh->vertex3f;
2763 GL_LockArrays(0, mesh->numverts);
2764 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2766 // increment stencil if backface is behind depthbuffer
2767 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2768 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2769 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2770 c_rtcached_shadowmeshes++;
2771 c_rtcached_shadowtris += mesh->numtriangles;
2772 // decrement stencil if frontface is behind depthbuffer
2773 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2774 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2776 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2777 c_rtcached_shadowmeshes++;
2778 c_rtcached_shadowtris += mesh->numtriangles;
2779 GL_LockArrays(0, 0);
2782 else if (numsurfaces)
2784 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2785 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2787 if (r_drawentities.integer)
2789 for (i = 0;i < r_refdef.numentities;i++)
2791 ent = r_refdef.entities[i];
2793 if (r_shadow_cull.integer)
2795 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2797 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2800 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2802 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2803 // light emitting entities should not cast their own shadow
2804 if (VectorLength2(relativelightorigin) < 0.1)
2806 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2807 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2808 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2809 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2810 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2811 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2812 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2817 if (!visiblevolumes)
2819 R_Shadow_Stage_Light(usestencil);
2821 ent = r_refdef.worldentity;
2822 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2824 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2825 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2826 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2827 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2828 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2829 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2830 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2831 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2832 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2834 R_Mesh_Matrix(&ent->matrix);
2835 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2836 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, NULL, NULL, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
2839 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2841 if (r_drawentities.integer)
2843 for (i = 0;i < r_refdef.numentities;i++)
2845 ent = r_refdef.entities[i];
2846 // can't draw transparent entity lighting here because
2847 // transparent meshes are deferred for later
2848 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
2850 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2851 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2852 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2853 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2854 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2855 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2856 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2857 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2858 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, ent->model->nummodelsurfaces, ent->model->surfacelist);
2865 void R_ShadowVolumeLighting(int visiblevolumes)
2871 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2872 R_Shadow_EditLights_Reload_f();
2876 memset(&m, 0, sizeof(m));
2879 GL_BlendFunc(GL_ONE, GL_ONE);
2880 GL_DepthMask(false);
2881 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2882 qglDisable(GL_CULL_FACE);
2883 GL_Color(0.0, 0.0125, 0.1, 1);
2886 R_Shadow_Stage_Begin();
2887 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2888 if (r_shadow_debuglight.integer >= 0)
2890 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2891 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2892 R_DrawRTLight(&light->rtlight, visiblevolumes);
2895 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2896 if (light->flags & flag)
2897 R_DrawRTLight(&light->rtlight, visiblevolumes);
2899 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2900 R_DrawRTLight(&light->rtlight, visiblevolumes);
2904 qglEnable(GL_CULL_FACE);
2905 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2908 R_Shadow_Stage_End();
2911 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2912 typedef struct suffixinfo_s
2915 qboolean flipx, flipy, flipdiagonal;
2918 static suffixinfo_t suffix[3][6] =
2921 {"px", false, false, false},
2922 {"nx", false, false, false},
2923 {"py", false, false, false},
2924 {"ny", false, false, false},
2925 {"pz", false, false, false},
2926 {"nz", false, false, false}
2929 {"posx", false, false, false},
2930 {"negx", false, false, false},
2931 {"posy", false, false, false},
2932 {"negy", false, false, false},
2933 {"posz", false, false, false},
2934 {"negz", false, false, false}
2937 {"rt", true, false, true},
2938 {"lf", false, true, true},
2939 {"ft", true, true, false},
2940 {"bk", false, false, false},
2941 {"up", true, false, true},
2942 {"dn", true, false, true}
2946 static int componentorder[4] = {0, 1, 2, 3};
2948 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2950 int i, j, cubemapsize;
2951 qbyte *cubemappixels, *image_rgba;
2952 rtexture_t *cubemaptexture;
2954 // must start 0 so the first loadimagepixels has no requested width/height
2956 cubemappixels = NULL;
2957 cubemaptexture = NULL;
2958 // keep trying different suffix groups (posx, px, rt) until one loads
2959 for (j = 0;j < 3 && !cubemappixels;j++)
2961 // load the 6 images in the suffix group
2962 for (i = 0;i < 6;i++)
2964 // generate an image name based on the base and and suffix
2965 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2967 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2969 // an image loaded, make sure width and height are equal
2970 if (image_width == image_height)
2972 // if this is the first image to load successfully, allocate the cubemap memory
2973 if (!cubemappixels && image_width >= 1)
2975 cubemapsize = image_width;
2976 // note this clears to black, so unavailable sides are black
2977 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2979 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2981 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);
2984 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2986 Mem_Free(image_rgba);
2990 // if a cubemap loaded, upload it
2993 if (!r_shadow_filters_texturepool)
2994 r_shadow_filters_texturepool = R_AllocTexturePool();
2995 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2996 Mem_Free(cubemappixels);
3000 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3001 for (j = 0;j < 3;j++)
3002 for (i = 0;i < 6;i++)
3003 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3004 Con_Print(" and was unable to find any of them.\n");
3006 return cubemaptexture;
3009 rtexture_t *R_Shadow_Cubemap(const char *basename)
3012 for (i = 0;i < numcubemaps;i++)
3013 if (!strcasecmp(cubemaps[i].basename, basename))
3014 return cubemaps[i].texture;
3015 if (i >= MAX_CUBEMAPS)
3018 strcpy(cubemaps[i].basename, basename);
3019 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3020 return cubemaps[i].texture;
3023 void R_Shadow_FreeCubemaps(void)
3026 R_FreeTexturePool(&r_shadow_filters_texturepool);
3029 dlight_t *R_Shadow_NewWorldLight(void)
3032 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3033 light->next = r_shadow_worldlightchain;
3034 r_shadow_worldlightchain = light;
3038 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)
3040 VectorCopy(origin, light->origin);
3041 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3042 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3043 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3044 light->color[0] = max(color[0], 0);
3045 light->color[1] = max(color[1], 0);
3046 light->color[2] = max(color[2], 0);
3047 light->radius = max(radius, 0);
3048 light->style = style;
3049 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3051 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3054 light->shadow = shadowenable;
3055 light->corona = corona;
3058 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3059 light->coronasizescale = coronasizescale;
3060 light->ambientscale = ambientscale;
3061 light->diffusescale = diffusescale;
3062 light->specularscale = specularscale;
3063 light->flags = flags;
3064 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3066 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3069 void R_Shadow_FreeWorldLight(dlight_t *light)
3071 dlight_t **lightpointer;
3072 R_RTLight_Uncompile(&light->rtlight);
3073 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3074 if (*lightpointer != light)
3075 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3076 *lightpointer = light->next;
3080 void R_Shadow_ClearWorldLights(void)
3082 while (r_shadow_worldlightchain)
3083 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3084 r_shadow_selectedlight = NULL;
3085 R_Shadow_FreeCubemaps();
3088 void R_Shadow_SelectLight(dlight_t *light)
3090 if (r_shadow_selectedlight)
3091 r_shadow_selectedlight->selected = false;
3092 r_shadow_selectedlight = light;
3093 if (r_shadow_selectedlight)
3094 r_shadow_selectedlight->selected = true;
3097 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3099 float scale = r_editlights_cursorgrid.value * 0.5f;
3100 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);
3103 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3106 const dlight_t *light;
3109 if (light->selected)
3110 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3113 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);
3116 void R_Shadow_DrawLightSprites(void)
3122 for (i = 0;i < 5;i++)
3124 lighttextures[i] = NULL;
3125 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3126 lighttextures[i] = pic->tex;
3129 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3130 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3131 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3134 void R_Shadow_SelectLightInView(void)
3136 float bestrating, rating, temp[3];
3137 dlight_t *best, *light;
3140 for (light = r_shadow_worldlightchain;light;light = light->next)
3142 VectorSubtract(light->origin, r_vieworigin, temp);
3143 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3146 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3147 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3149 bestrating = rating;
3154 R_Shadow_SelectLight(best);
3157 void R_Shadow_LoadWorldLights(void)
3159 int n, a, style, shadow, flags;
3160 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3161 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3162 if (r_refdef.worldmodel == NULL)
3164 Con_Print("No map loaded.\n");
3167 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3168 strlcat (name, ".rtlights", sizeof (name));
3169 lightsstring = FS_LoadFile(name, tempmempool, false);
3179 for (;COM_Parse(t, true) && strcmp(
3180 if (COM_Parse(t, true))
3182 if (com_token[0] == '!')
3185 origin[0] = atof(com_token+1);
3188 origin[0] = atof(com_token);
3193 while (*s && *s != '\n' && *s != '\r')
3199 // check for modifier flags
3206 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);
3209 flags = LIGHTFLAG_REALTIMEMODE;
3217 coronasizescale = 0.25f;
3219 VectorClear(angles);
3222 if (a < 9 || !strcmp(cubemapname, "\"\""))
3224 // remove quotes on cubemapname
3225 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3227 cubemapname[strlen(cubemapname)-1] = 0;
3228 strcpy(cubemapname, cubemapname + 1);
3232 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);
3235 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3236 radius *= r_editlights_rtlightssizescale.value;
3237 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3245 Con_Printf("invalid rtlights file \"%s\"\n", name);
3246 Mem_Free(lightsstring);
3250 void R_Shadow_SaveWorldLights(void)
3253 int bufchars, bufmaxchars;
3255 char name[MAX_QPATH];
3257 if (!r_shadow_worldlightchain)
3259 if (r_refdef.worldmodel == NULL)
3261 Con_Print("No map loaded.\n");
3264 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3265 strlcat (name, ".rtlights", sizeof (name));
3266 bufchars = bufmaxchars = 0;
3268 for (light = r_shadow_worldlightchain;light;light = light->next)
3270 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3271 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);
3272 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3273 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]);
3275 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);
3276 if (bufchars + (int) strlen(line) > bufmaxchars)
3278 bufmaxchars = bufchars + strlen(line) + 2048;
3280 buf = Mem_Alloc(tempmempool, bufmaxchars);
3284 memcpy(buf, oldbuf, bufchars);
3290 memcpy(buf + bufchars, line, strlen(line));
3291 bufchars += strlen(line);
3295 FS_WriteFile(name, buf, bufchars);
3300 void R_Shadow_LoadLightsFile(void)
3303 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3304 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3305 if (r_refdef.worldmodel == NULL)
3307 Con_Print("No map loaded.\n");
3310 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3311 strlcat (name, ".lights", sizeof (name));
3312 lightsstring = FS_LoadFile(name, tempmempool, false);
3320 while (*s && *s != '\n' && *s != '\r')
3326 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);
3330 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);
3333 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3334 radius = bound(15, radius, 4096);
3335 VectorScale(color, (2.0f / (8388608.0f)), color);
3336 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3344 Con_Printf("invalid lights file \"%s\"\n", name);
3345 Mem_Free(lightsstring);
3349 // tyrlite/hmap2 light types in the delay field
3350 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3352 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3354 int entnum, style, islight, skin, pflags, effects, type, n;
3357 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3358 char key[256], value[1024];
3360 if (r_refdef.worldmodel == NULL)
3362 Con_Print("No map loaded.\n");
3365 // try to load a .ent file first
3366 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3367 strlcat (key, ".ent", sizeof (key));
3368 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3369 // and if that is not found, fall back to the bsp file entity string
3371 data = r_refdef.worldmodel->brush.entities;
3374 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3376 type = LIGHTTYPE_MINUSX;
3377 origin[0] = origin[1] = origin[2] = 0;
3378 originhack[0] = originhack[1] = originhack[2] = 0;
3379 angles[0] = angles[1] = angles[2] = 0;
3380 color[0] = color[1] = color[2] = 1;
3381 light[0] = light[1] = light[2] = 1;light[3] = 300;
3382 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3392 if (!COM_ParseToken(&data, false))
3394 if (com_token[0] == '}')
3395 break; // end of entity
3396 if (com_token[0] == '_')
3397 strcpy(key, com_token + 1);
3399 strcpy(key, com_token);
3400 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3401 key[strlen(key)-1] = 0;
3402 if (!COM_ParseToken(&data, false))
3404 strcpy(value, com_token);
3406 // now that we have the key pair worked out...
3407 if (!strcmp("light", key))
3409 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3413 light[0] = vec[0] * (1.0f / 256.0f);
3414 light[1] = vec[0] * (1.0f / 256.0f);
3415 light[2] = vec[0] * (1.0f / 256.0f);
3421 light[0] = vec[0] * (1.0f / 255.0f);
3422 light[1] = vec[1] * (1.0f / 255.0f);
3423 light[2] = vec[2] * (1.0f / 255.0f);
3427 else if (!strcmp("delay", key))
3429 else if (!strcmp("origin", key))
3430 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3431 else if (!strcmp("angle", key))
3432 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3433 else if (!strcmp("angles", key))
3434 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3435 else if (!strcmp("color", key))
3436 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3437 else if (!strcmp("wait", key))
3438 fadescale = atof(value);
3439 else if (!strcmp("classname", key))
3441 if (!strncmp(value, "light", 5))
3444 if (!strcmp(value, "light_fluoro"))
3449 overridecolor[0] = 1;
3450 overridecolor[1] = 1;
3451 overridecolor[2] = 1;
3453 if (!strcmp(value, "light_fluorospark"))
3458 overridecolor[0] = 1;
3459 overridecolor[1] = 1;
3460 overridecolor[2] = 1;
3462 if (!strcmp(value, "light_globe"))
3467 overridecolor[0] = 1;
3468 overridecolor[1] = 0.8;
3469 overridecolor[2] = 0.4;
3471 if (!strcmp(value, "light_flame_large_yellow"))
3476 overridecolor[0] = 1;
3477 overridecolor[1] = 0.5;
3478 overridecolor[2] = 0.1;
3480 if (!strcmp(value, "light_flame_small_yellow"))
3485 overridecolor[0] = 1;
3486 overridecolor[1] = 0.5;
3487 overridecolor[2] = 0.1;
3489 if (!strcmp(value, "light_torch_small_white"))
3494 overridecolor[0] = 1;
3495 overridecolor[1] = 0.5;
3496 overridecolor[2] = 0.1;
3498 if (!strcmp(value, "light_torch_small_walltorch"))
3503 overridecolor[0] = 1;
3504 overridecolor[1] = 0.5;
3505 overridecolor[2] = 0.1;
3509 else if (!strcmp("style", key))
3510 style = atoi(value);
3511 else if (r_refdef.worldmodel->type == mod_brushq3)
3513 if (!strcmp("scale", key))
3514 lightscale = atof(value);
3515 if (!strcmp("fade", key))
3516 fadescale = atof(value);
3518 else if (!strcmp("skin", key))
3519 skin = (int)atof(value);
3520 else if (!strcmp("pflags", key))
3521 pflags = (int)atof(value);
3522 else if (!strcmp("effects", key))
3523 effects = (int)atof(value);
3527 if (lightscale <= 0)
3531 if (color[0] == color[1] && color[0] == color[2])
3533 color[0] *= overridecolor[0];
3534 color[1] *= overridecolor[1];
3535 color[2] *= overridecolor[2];
3537 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3538 color[0] = color[0] * light[0];
3539 color[1] = color[1] * light[1];
3540 color[2] = color[2] * light[2];
3543 case LIGHTTYPE_MINUSX:
3545 case LIGHTTYPE_RECIPX:
3547 VectorScale(color, (1.0f / 16.0f), color);
3549 case LIGHTTYPE_RECIPXX:
3551 VectorScale(color, (1.0f / 16.0f), color);
3554 case LIGHTTYPE_NONE:
3558 case LIGHTTYPE_MINUSXX:
3561 VectorAdd(origin, originhack, origin);
3563 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);
3566 Mem_Free(entfiledata);
3570 void R_Shadow_SetCursorLocationForView(void)
3572 vec_t dist, push, frac;
3573 vec3_t dest, endpos, normal;
3574 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3575 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3578 dist = frac * r_editlights_cursordistance.value;
3579 push = r_editlights_cursorpushback.value;
3583 VectorMA(endpos, push, r_viewforward, endpos);
3584 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3586 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3587 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3588 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3591 void R_Shadow_UpdateWorldLightSelection(void)
3593 if (r_editlights.integer)
3595 R_Shadow_SetCursorLocationForView();
3596 R_Shadow_SelectLightInView();
3597 R_Shadow_DrawLightSprites();
3600 R_Shadow_SelectLight(NULL);
3603 void R_Shadow_EditLights_Clear_f(void)
3605 R_Shadow_ClearWorldLights();
3608 void R_Shadow_EditLights_Reload_f(void)
3610 if (!r_refdef.worldmodel)
3612 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3613 R_Shadow_ClearWorldLights();
3614 R_Shadow_LoadWorldLights();
3615 if (r_shadow_worldlightchain == NULL)
3617 R_Shadow_LoadLightsFile();
3618 if (r_shadow_worldlightchain == NULL)
3619 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3623 void R_Shadow_EditLights_Save_f(void)
3625 if (!r_refdef.worldmodel)
3627 R_Shadow_SaveWorldLights();
3630 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3632 R_Shadow_ClearWorldLights();
3633 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3636 void R_Shadow_EditLights_ImportLightsFile_f(void)
3638 R_Shadow_ClearWorldLights();
3639 R_Shadow_LoadLightsFile();
3642 void R_Shadow_EditLights_Spawn_f(void)
3645 if (!r_editlights.integer)
3647 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3650 if (Cmd_Argc() != 1)
3652 Con_Print("r_editlights_spawn does not take parameters\n");
3655 color[0] = color[1] = color[2] = 1;
3656 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3659 void R_Shadow_EditLights_Edit_f(void)
3661 vec3_t origin, angles, color;
3662 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3663 int style, shadows, flags, normalmode, realtimemode;
3664 char cubemapname[1024];
3665 if (!r_editlights.integer)
3667 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3670 if (!r_shadow_selectedlight)
3672 Con_Print("No selected light.\n");
3675 VectorCopy(r_shadow_selectedlight->origin, origin);
3676 VectorCopy(r_shadow_selectedlight->angles, angles);
3677 VectorCopy(r_shadow_selectedlight->color, color);
3678 radius = r_shadow_selectedlight->radius;
3679 style = r_shadow_selectedlight->style;
3680 if (r_shadow_selectedlight->cubemapname)
3681 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3684 shadows = r_shadow_selectedlight->shadow;
3685 corona = r_shadow_selectedlight->corona;
3686 coronasizescale = r_shadow_selectedlight->coronasizescale;
3687 ambientscale = r_shadow_selectedlight->ambientscale;
3688 diffusescale = r_shadow_selectedlight->diffusescale;
3689 specularscale = r_shadow_selectedlight->specularscale;
3690 flags = r_shadow_selectedlight->flags;
3691 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3692 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3693 if (!strcmp(Cmd_Argv(1), "origin"))
3695 if (Cmd_Argc() != 5)
3697 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3700 origin[0] = atof(Cmd_Argv(2));
3701 origin[1] = atof(Cmd_Argv(3));
3702 origin[2] = atof(Cmd_Argv(4));
3704 else if (!strcmp(Cmd_Argv(1), "originx"))
3706 if (Cmd_Argc() != 3)
3708 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3711 origin[0] = atof(Cmd_Argv(2));
3713 else if (!strcmp(Cmd_Argv(1), "originy"))
3715 if (Cmd_Argc() != 3)
3717 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3720 origin[1] = atof(Cmd_Argv(2));
3722 else if (!strcmp(Cmd_Argv(1), "originz"))
3724 if (Cmd_Argc() != 3)
3726 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3729 origin[2] = atof(Cmd_Argv(2));
3731 else if (!strcmp(Cmd_Argv(1), "move"))
3733 if (Cmd_Argc() != 5)
3735 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3738 origin[0] += atof(Cmd_Argv(2));
3739 origin[1] += atof(Cmd_Argv(3));
3740 origin[2] += atof(Cmd_Argv(4));
3742 else if (!strcmp(Cmd_Argv(1), "movex"))
3744 if (Cmd_Argc() != 3)
3746 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3749 origin[0] += atof(Cmd_Argv(2));
3751 else if (!strcmp(Cmd_Argv(1), "movey"))
3753 if (Cmd_Argc() != 3)
3755 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3758 origin[1] += atof(Cmd_Argv(2));
3760 else if (!strcmp(Cmd_Argv(1), "movez"))
3762 if (Cmd_Argc() != 3)
3764 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3767 origin[2] += atof(Cmd_Argv(2));
3769 else if (!strcmp(Cmd_Argv(1), "angles"))
3771 if (Cmd_Argc() != 5)
3773 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3776 angles[0] = atof(Cmd_Argv(2));
3777 angles[1] = atof(Cmd_Argv(3));
3778 angles[2] = atof(Cmd_Argv(4));
3780 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3782 if (Cmd_Argc() != 3)
3784 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3787 angles[0] = atof(Cmd_Argv(2));
3789 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3791 if (Cmd_Argc() != 3)
3793 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3796 angles[1] = atof(Cmd_Argv(2));
3798 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3800 if (Cmd_Argc() != 3)
3802 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3805 angles[2] = atof(Cmd_Argv(2));
3807 else if (!strcmp(Cmd_Argv(1), "color"))
3809 if (Cmd_Argc() != 5)
3811 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3814 color[0] = atof(Cmd_Argv(2));
3815 color[1] = atof(Cmd_Argv(3));
3816 color[2] = atof(Cmd_Argv(4));
3818 else if (!strcmp(Cmd_Argv(1), "radius"))
3820 if (Cmd_Argc() != 3)
3822 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3825 radius = atof(Cmd_Argv(2));
3827 else if (!strcmp(Cmd_Argv(1), "style"))
3829 if (Cmd_Argc() != 3)
3831 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3834 style = atoi(Cmd_Argv(2));
3836 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3840 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3843 if (Cmd_Argc() == 3)
3844 strcpy(cubemapname, Cmd_Argv(2));
3848 else if (!strcmp(Cmd_Argv(1), "shadows"))
3850 if (Cmd_Argc() != 3)
3852 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3855 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3857 else if (!strcmp(Cmd_Argv(1), "corona"))
3859 if (Cmd_Argc() != 3)
3861 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3864 corona = atof(Cmd_Argv(2));
3866 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3868 if (Cmd_Argc() != 3)
3870 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3873 coronasizescale = atof(Cmd_Argv(2));
3875 else if (!strcmp(Cmd_Argv(1), "ambient"))
3877 if (Cmd_Argc() != 3)
3879 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3882 ambientscale = atof(Cmd_Argv(2));
3884 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3886 if (Cmd_Argc() != 3)
3888 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3891 diffusescale = atof(Cmd_Argv(2));
3893 else if (!strcmp(Cmd_Argv(1), "specular"))
3895 if (Cmd_Argc() != 3)
3897 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3900 specularscale = atof(Cmd_Argv(2));
3902 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3904 if (Cmd_Argc() != 3)
3906 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3909 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3911 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3913 if (Cmd_Argc() != 3)
3915 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3918 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3922 Con_Print("usage: r_editlights_edit [property] [value]\n");
3923 Con_Print("Selected light's properties:\n");
3924 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3925 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3926 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3927 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3928 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3929 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3930 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3931 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3932 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3933 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3934 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3935 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3936 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3937 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3940 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3941 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3944 void R_Shadow_EditLights_EditAll_f(void)
3948 if (!r_editlights.integer)
3950 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3954 for (light = r_shadow_worldlightchain;light;light = light->next)
3956 R_Shadow_SelectLight(light);
3957 R_Shadow_EditLights_Edit_f();
3961 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3963 int lightnumber, lightcount;
3967 if (!r_editlights.integer)
3973 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3974 if (light == r_shadow_selectedlight)
3975 lightnumber = lightcount;
3976 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;
3977 if (r_shadow_selectedlight == NULL)
3979 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3980 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;
3981 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;
3982 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;
3983 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3984 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3985 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3986 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;
3987 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3988 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3989 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3990 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3991 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3992 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;
3993 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;
3996 void R_Shadow_EditLights_ToggleShadow_f(void)
3998 if (!r_editlights.integer)
4000 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4003 if (!r_shadow_selectedlight)
4005 Con_Print("No selected light.\n");
4008 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);
4011 void R_Shadow_EditLights_ToggleCorona_f(void)
4013 if (!r_editlights.integer)
4015 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4018 if (!r_shadow_selectedlight)
4020 Con_Print("No selected light.\n");
4023 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);
4026 void R_Shadow_EditLights_Remove_f(void)
4028 if (!r_editlights.integer)
4030 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4033 if (!r_shadow_selectedlight)
4035 Con_Print("No selected light.\n");
4038 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4039 r_shadow_selectedlight = NULL;
4042 void R_Shadow_EditLights_Help_f(void)
4045 "Documentation on r_editlights system:\n"
4047 "r_editlights : enable/disable editing mode\n"
4048 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4049 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4050 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4051 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4052 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4053 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4054 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4056 "r_editlights_help : this help\n"
4057 "r_editlights_clear : remove all lights\n"
4058 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4059 "r_editlights_save : save to .rtlights file\n"
4060 "r_editlights_spawn : create a light with default settings\n"
4061 "r_editlights_edit command : edit selected light - more documentation below\n"
4062 "r_editlights_remove : remove selected light\n"
4063 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4064 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4065 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4067 "origin x y z : set light location\n"
4068 "originx x: set x component of light location\n"
4069 "originy y: set y component of light location\n"
4070 "originz z: set z component of light location\n"
4071 "move x y z : adjust light location\n"
4072 "movex x: adjust x component of light location\n"
4073 "movey y: adjust y component of light location\n"
4074 "movez z: adjust z component of light location\n"
4075 "angles x y z : set light angles\n"
4076 "anglesx x: set x component of light angles\n"
4077 "anglesy y: set y component of light angles\n"
4078 "anglesz z: set z component of light angles\n"
4079 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4080 "radius radius : set radius (size) of light\n"
4081 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4082 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4083 "shadows 1/0 : turn on/off shadows\n"
4084 "corona n : set corona intensity\n"
4085 "coronasize n : set corona size (0-1)\n"
4086 "ambient n : set ambient intensity (0-1)\n"
4087 "diffuse n : set diffuse intensity (0-1)\n"
4088 "specular n : set specular intensity (0-1)\n"
4089 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4090 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4091 "<nothing> : print light properties to console\n"
4095 void R_Shadow_EditLights_CopyInfo_f(void)
4097 if (!r_editlights.integer)
4099 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4102 if (!r_shadow_selectedlight)
4104 Con_Print("No selected light.\n");
4107 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4108 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4109 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4110 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4111 if (r_shadow_selectedlight->cubemapname)
4112 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4114 r_shadow_bufferlight.cubemapname[0] = 0;
4115 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4116 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4117 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4118 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4119 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4120 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4121 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4124 void R_Shadow_EditLights_PasteInfo_f(void)
4126 if (!r_editlights.integer)
4128 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4131 if (!r_shadow_selectedlight)
4133 Con_Print("No selected light.\n");
4136 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);
4139 void R_Shadow_EditLights_Init(void)
4141 Cvar_RegisterVariable(&r_editlights);
4142 Cvar_RegisterVariable(&r_editlights_cursordistance);
4143 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4144 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4145 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4146 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4147 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4148 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4149 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4150 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4151 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4152 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4153 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4154 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4155 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4156 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4157 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4158 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4159 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4160 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4161 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4162 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);