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_distance", "1024"};
197 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
198 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
199 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "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_EnlargeClusterBuffer(int numclusters)
675 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
676 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
678 if (r_shadow_buffer_clusterpvs)
679 Mem_Free(r_shadow_buffer_clusterpvs);
680 if (r_shadow_buffer_clusterlist)
681 Mem_Free(r_shadow_buffer_clusterlist);
682 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
683 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
684 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
688 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
690 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
691 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
693 if (r_shadow_buffer_surfacepvs)
694 Mem_Free(r_shadow_buffer_surfacepvs);
695 if (r_shadow_buffer_surfacelist)
696 Mem_Free(r_shadow_buffer_surfacelist);
697 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
698 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
699 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
703 void R_Shadow_PrepareShadowMark(int numtris)
705 // make sure shadowmark is big enough for this volume
706 if (maxshadowmark < numtris)
708 maxshadowmark = numtris;
710 Mem_Free(shadowmark);
712 Mem_Free(shadowmarklist);
713 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
714 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
718 // if shadowmarkcount wrapped we clear the array and adjust accordingly
719 if (shadowmarkcount == 0)
722 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
727 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)
730 int outtriangles = 0, outvertices = 0;
734 if (maxvertexupdate < innumvertices)
736 maxvertexupdate = innumvertices;
738 Mem_Free(vertexupdate);
740 Mem_Free(vertexremap);
741 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
742 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
746 if (vertexupdatenum == 0)
749 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
750 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
753 for (i = 0;i < numshadowmarktris;i++)
754 shadowmark[shadowmarktris[i]] = shadowmarkcount;
756 for (i = 0;i < numshadowmarktris;i++)
758 element = inelement3i + shadowmarktris[i] * 3;
759 // make sure the vertices are created
760 for (j = 0;j < 3;j++)
762 if (vertexupdate[element[j]] != vertexupdatenum)
764 float ratio, direction[3];
765 vertexupdate[element[j]] = vertexupdatenum;
766 vertexremap[element[j]] = outvertices;
767 vertex = invertex3f + element[j] * 3;
768 // project one copy of the vertex to the sphere radius of the light
769 // (FIXME: would projecting it to the light box be better?)
770 VectorSubtract(vertex, projectorigin, direction);
771 ratio = projectdistance / VectorLength(direction);
772 VectorCopy(vertex, outvertex3f);
773 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
780 for (i = 0;i < numshadowmarktris;i++)
782 int remappedelement[3];
784 const int *neighbortriangle;
786 markindex = shadowmarktris[i] * 3;
787 element = inelement3i + markindex;
788 neighbortriangle = inneighbor3i + markindex;
789 // output the front and back triangles
790 outelement3i[0] = vertexremap[element[0]];
791 outelement3i[1] = vertexremap[element[1]];
792 outelement3i[2] = vertexremap[element[2]];
793 outelement3i[3] = vertexremap[element[2]] + 1;
794 outelement3i[4] = vertexremap[element[1]] + 1;
795 outelement3i[5] = vertexremap[element[0]] + 1;
799 // output the sides (facing outward from this triangle)
800 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
802 remappedelement[0] = vertexremap[element[0]];
803 remappedelement[1] = vertexremap[element[1]];
804 outelement3i[0] = remappedelement[1];
805 outelement3i[1] = remappedelement[0];
806 outelement3i[2] = remappedelement[0] + 1;
807 outelement3i[3] = remappedelement[1];
808 outelement3i[4] = remappedelement[0] + 1;
809 outelement3i[5] = remappedelement[1] + 1;
814 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
816 remappedelement[1] = vertexremap[element[1]];
817 remappedelement[2] = vertexremap[element[2]];
818 outelement3i[0] = remappedelement[2];
819 outelement3i[1] = remappedelement[1];
820 outelement3i[2] = remappedelement[1] + 1;
821 outelement3i[3] = remappedelement[2];
822 outelement3i[4] = remappedelement[1] + 1;
823 outelement3i[5] = remappedelement[2] + 1;
828 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
830 remappedelement[0] = vertexremap[element[0]];
831 remappedelement[2] = vertexremap[element[2]];
832 outelement3i[0] = remappedelement[0];
833 outelement3i[1] = remappedelement[2];
834 outelement3i[2] = remappedelement[2] + 1;
835 outelement3i[3] = remappedelement[0];
836 outelement3i[4] = remappedelement[2] + 1;
837 outelement3i[5] = remappedelement[0] + 1;
844 *outnumvertices = outvertices;
848 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)
851 if (projectdistance < 0.1)
853 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
856 if (!numverts || !nummarktris)
858 // make sure shadowelements is big enough for this volume
859 if (maxshadowelements < nummarktris * 24)
860 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
861 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
862 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
865 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)
870 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
872 tend = firsttriangle + numtris;
873 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
874 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
875 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
877 // surface box entirely inside light box, no box cull
878 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
879 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
880 shadowmarklist[numshadowmark++] = t;
884 // surface box not entirely inside light box, cull each triangle
885 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
887 v[0] = invertex3f + e[0] * 3;
888 v[1] = invertex3f + e[1] * 3;
889 v[2] = invertex3f + e[2] * 3;
890 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
891 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
892 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
893 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
894 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
895 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
896 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
897 shadowmarklist[numshadowmark++] = t;
902 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
905 if (r_shadow_compilingrtlight)
907 // if we're compiling an rtlight, capture the mesh
908 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
911 memset(&m, 0, sizeof(m));
912 m.pointer_vertex = vertex3f;
914 GL_LockArrays(0, numvertices);
915 if (r_shadowstage == SHADOWSTAGE_STENCIL)
917 // increment stencil if backface is behind depthbuffer
918 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
919 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
920 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
922 c_rt_shadowtris += numtriangles;
923 // decrement stencil if frontface is behind depthbuffer
924 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
925 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
927 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
929 c_rt_shadowtris += numtriangles;
933 static void R_Shadow_MakeTextures(void)
935 int x, y, z, d, side;
936 float v[3], s, t, intensity;
938 R_FreeTexturePool(&r_shadow_texturepool);
939 r_shadow_texturepool = R_AllocTexturePool();
940 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
941 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
943 #define ATTEN2DSIZE 64
944 #define ATTEN3DSIZE 32
945 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
946 r_shadow_blankwhitecubetexture = NULL;
947 r_shadow_normalcubetexture = NULL;
948 if (gl_texturecubemap)
950 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
951 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
952 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
953 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
954 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
955 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
956 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
957 for (side = 0;side < 6;side++)
959 for (y = 0;y < NORMSIZE;y++)
961 for (x = 0;x < NORMSIZE;x++)
963 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
964 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
998 intensity = 127.0f / sqrt(DotProduct(v, v));
999 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1000 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1001 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1002 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1006 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1008 for (y = 0;y < ATTEN2DSIZE;y++)
1010 for (x = 0;x < ATTEN2DSIZE;x++)
1012 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1013 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1015 intensity = 1.0f - sqrt(DotProduct(v, v));
1017 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1018 d = bound(0, intensity, 255);
1019 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1020 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1021 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1022 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1025 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1026 if (r_shadow_texture3d.integer)
1028 for (z = 0;z < ATTEN3DSIZE;z++)
1030 for (y = 0;y < ATTEN3DSIZE;y++)
1032 for (x = 0;x < ATTEN3DSIZE;x++)
1034 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1035 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1036 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1037 intensity = 1.0f - sqrt(DotProduct(v, v));
1039 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1040 d = bound(0, intensity, 255);
1041 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1042 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1043 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1044 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1048 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1053 void R_Shadow_ValidateCvars(void)
1055 if (r_shadow_texture3d.integer && !gl_texture3d)
1056 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1057 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1058 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1061 void R_Shadow_Stage_Begin(void)
1065 R_Shadow_ValidateCvars();
1067 if (!r_shadow_attenuation2dtexture
1068 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1069 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1070 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1071 R_Shadow_MakeTextures();
1073 memset(&m, 0, sizeof(m));
1074 GL_BlendFunc(GL_ONE, GL_ZERO);
1075 GL_DepthMask(false);
1078 GL_Color(0, 0, 0, 1);
1079 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1080 qglEnable(GL_CULL_FACE);
1081 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1082 r_shadowstage = SHADOWSTAGE_NONE;
1085 void R_Shadow_Stage_ShadowVolumes(void)
1088 memset(&m, 0, sizeof(m));
1090 GL_Color(1, 1, 1, 1);
1091 GL_ColorMask(0, 0, 0, 0);
1092 GL_BlendFunc(GL_ONE, GL_ZERO);
1093 GL_DepthMask(false);
1095 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1096 //if (r_shadow_shadow_polygonoffset.value != 0)
1098 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1099 // qglEnable(GL_POLYGON_OFFSET_FILL);
1102 // qglDisable(GL_POLYGON_OFFSET_FILL);
1103 qglDepthFunc(GL_LESS);
1104 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1105 qglEnable(GL_STENCIL_TEST);
1106 qglStencilFunc(GL_ALWAYS, 128, ~0);
1107 if (gl_ext_stenciltwoside.integer)
1109 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1110 qglDisable(GL_CULL_FACE);
1111 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1112 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1114 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1115 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1117 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1121 r_shadowstage = SHADOWSTAGE_STENCIL;
1122 qglEnable(GL_CULL_FACE);
1124 // this is changed by every shadow render so its value here is unimportant
1125 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1127 GL_Clear(GL_STENCIL_BUFFER_BIT);
1129 // LordHavoc note: many shadow volumes reside entirely inside the world
1130 // (that is to say they are entirely bounded by their lit surfaces),
1131 // which can be optimized by handling things as an inverted light volume,
1132 // with the shadow boundaries of the world being simulated by an altered
1133 // (129) bias to stencil clearing on such lights
1134 // FIXME: generate inverted light volumes for use as shadow volumes and
1135 // optimize for them as noted above
1138 void R_Shadow_Stage_Light(int shadowtest)
1141 memset(&m, 0, sizeof(m));
1143 GL_BlendFunc(GL_ONE, GL_ONE);
1144 GL_DepthMask(false);
1146 qglPolygonOffset(0, 0);
1147 //qglDisable(GL_POLYGON_OFFSET_FILL);
1148 GL_Color(1, 1, 1, 1);
1149 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1150 qglDepthFunc(GL_EQUAL);
1151 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1152 qglEnable(GL_CULL_FACE);
1154 qglEnable(GL_STENCIL_TEST);
1156 qglDisable(GL_STENCIL_TEST);
1157 if (gl_support_stenciltwoside)
1158 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1160 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1161 // only draw light where this geometry was already rendered AND the
1162 // stencil is 128 (values other than this mean shadow)
1163 qglStencilFunc(GL_EQUAL, 128, ~0);
1164 r_shadowstage = SHADOWSTAGE_LIGHT;
1168 void R_Shadow_Stage_End(void)
1171 memset(&m, 0, sizeof(m));
1173 GL_BlendFunc(GL_ONE, GL_ZERO);
1176 qglPolygonOffset(0, 0);
1177 //qglDisable(GL_POLYGON_OFFSET_FILL);
1178 GL_Color(1, 1, 1, 1);
1179 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1180 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1181 qglDepthFunc(GL_LEQUAL);
1182 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1183 qglDisable(GL_STENCIL_TEST);
1184 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1185 if (gl_support_stenciltwoside)
1186 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1188 qglStencilFunc(GL_ALWAYS, 128, ~0);
1189 r_shadowstage = SHADOWSTAGE_NONE;
1192 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1194 int i, ix1, iy1, ix2, iy2;
1195 float x1, y1, x2, y2, x, y, f;
1196 vec3_t smins, smaxs;
1198 if (!r_shadow_scissor.integer)
1200 // if view is inside the box, just say yes it's visible
1201 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1203 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1206 for (i = 0;i < 3;i++)
1208 if (r_viewforward[i] >= 0)
1219 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1220 if (DotProduct(r_viewforward, v2) <= f)
1222 // entirely behind nearclip plane
1225 if (DotProduct(r_viewforward, v) >= f)
1227 // entirely infront of nearclip plane
1228 x1 = y1 = x2 = y2 = 0;
1229 for (i = 0;i < 8;i++)
1231 v[0] = (i & 1) ? mins[0] : maxs[0];
1232 v[1] = (i & 2) ? mins[1] : maxs[1];
1233 v[2] = (i & 4) ? mins[2] : maxs[2];
1235 GL_TransformToScreen(v, v2);
1236 //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]);
1255 // clipped by nearclip plane
1256 // this is nasty and crude...
1257 // create viewspace bbox
1258 for (i = 0;i < 8;i++)
1260 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1261 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1262 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1263 v2[0] = -DotProduct(v, r_viewleft);
1264 v2[1] = DotProduct(v, r_viewup);
1265 v2[2] = DotProduct(v, r_viewforward);
1268 if (smins[0] > v2[0]) smins[0] = v2[0];
1269 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1270 if (smins[1] > v2[1]) smins[1] = v2[1];
1271 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1272 if (smins[2] > v2[2]) smins[2] = v2[2];
1273 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1277 smins[0] = smaxs[0] = v2[0];
1278 smins[1] = smaxs[1] = v2[1];
1279 smins[2] = smaxs[2] = v2[2];
1282 // now we have a bbox in viewspace
1283 // clip it to the view plane
1286 // return true if that culled the box
1287 if (smins[2] >= smaxs[2])
1289 // ok some of it is infront of the view, transform each corner back to
1290 // worldspace and then to screenspace and make screen rect
1291 // initialize these variables just to avoid compiler warnings
1292 x1 = y1 = x2 = y2 = 0;
1293 for (i = 0;i < 8;i++)
1295 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1296 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1297 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1298 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1299 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1300 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1302 GL_TransformToScreen(v, v2);
1303 //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]);
1320 // this code doesn't handle boxes with any points behind view properly
1321 x1 = 1000;x2 = -1000;
1322 y1 = 1000;y2 = -1000;
1323 for (i = 0;i < 8;i++)
1325 v[0] = (i & 1) ? mins[0] : maxs[0];
1326 v[1] = (i & 2) ? mins[1] : maxs[1];
1327 v[2] = (i & 4) ? mins[2] : maxs[2];
1329 GL_TransformToScreen(v, v2);
1330 //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]);
1348 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1349 if (ix1 < r_view_x) ix1 = r_view_x;
1350 if (iy1 < r_view_y) iy1 = r_view_y;
1351 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1352 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1353 if (ix2 <= ix1 || iy2 <= iy1)
1355 // set up the scissor rectangle
1356 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1357 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1358 //qglEnable(GL_SCISSOR_TEST);
1363 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1365 float *color4f = varray_color4f;
1366 float dist, dot, intensity, v[3], n[3];
1367 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1369 Matrix4x4_Transform(m, vertex3f, v);
1370 if ((dist = DotProduct(v, v)) < 1)
1372 Matrix4x4_Transform3x3(m, normal3f, n);
1373 if ((dot = DotProduct(n, v)) > 0)
1376 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1377 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1378 VectorScale(lightcolor, intensity, color4f);
1383 VectorClear(color4f);
1389 VectorClear(color4f);
1395 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1397 float *color4f = varray_color4f;
1398 float dist, dot, intensity, v[3], n[3];
1399 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1401 Matrix4x4_Transform(m, vertex3f, v);
1402 if ((dist = fabs(v[2])) < 1)
1404 Matrix4x4_Transform3x3(m, normal3f, n);
1405 if ((dot = DotProduct(n, v)) > 0)
1407 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1408 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1409 VectorScale(lightcolor, intensity, color4f);
1414 VectorClear(color4f);
1420 VectorClear(color4f);
1426 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1428 float *color4f = varray_color4f;
1429 float dot, intensity, v[3], n[3];
1430 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1432 Matrix4x4_Transform(m, vertex3f, v);
1433 Matrix4x4_Transform3x3(m, normal3f, n);
1434 if ((dot = DotProduct(n, v)) > 0)
1436 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1437 VectorScale(lightcolor, intensity, color4f);
1442 VectorClear(color4f);
1448 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1450 float *color4f = varray_color4f;
1451 float dist, intensity, v[3];
1452 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1454 Matrix4x4_Transform(m, vertex3f, v);
1455 if ((dist = DotProduct(v, v)) < 1)
1458 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1459 VectorScale(lightcolor, intensity, color4f);
1464 VectorClear(color4f);
1470 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1472 float *color4f = varray_color4f;
1473 float dist, intensity, v[3];
1474 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1476 Matrix4x4_Transform(m, vertex3f, v);
1477 if ((dist = fabs(v[2])) < 1)
1479 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1480 VectorScale(lightcolor, intensity, color4f);
1485 VectorClear(color4f);
1491 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1492 #define USETEXMATRIX
1494 #ifndef USETEXMATRIX
1495 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1496 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1497 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1501 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1502 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1503 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1510 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1514 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1515 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1523 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)
1527 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1529 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1530 // the cubemap normalizes this for us
1531 out3f[0] = DotProduct(svector3f, lightdir);
1532 out3f[1] = DotProduct(tvector3f, lightdir);
1533 out3f[2] = DotProduct(normal3f, lightdir);
1537 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)
1540 float lightdir[3], eyedir[3], halfdir[3];
1541 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1543 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1544 VectorNormalizeFast(lightdir);
1545 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1546 VectorNormalizeFast(eyedir);
1547 VectorAdd(lightdir, eyedir, halfdir);
1548 // the cubemap normalizes this for us
1549 out3f[0] = DotProduct(svector3f, halfdir);
1550 out3f[1] = DotProduct(tvector3f, halfdir);
1551 out3f[2] = DotProduct(normal3f, halfdir);
1555 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 *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
1558 float color[3], color2[3], colorscale;
1560 // FIXME: support EF_NODEPTHTEST
1561 GL_DepthMask(false);
1564 bumptexture = r_texture_blanknormalmap;
1565 specularscale *= r_shadow_glossintensity.value;
1568 if (r_shadow_gloss.integer >= 2)
1570 glosstexture = r_texture_white;
1571 specularscale *= r_shadow_gloss2intensity.value;
1575 glosstexture = r_texture_black;
1579 if (r_shadow_gloss.integer < 1)
1582 lightcubemap = r_shadow_blankwhitecubetexture;
1583 if (ambientscale + diffusescale + specularscale < 0.01)
1585 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1587 unsigned int perm, prog;
1588 // GLSL shader path (GFFX5200, Radeon 9500)
1589 memset(&m, 0, sizeof(m));
1590 m.pointer_vertex = vertex3f;
1591 m.pointer_texcoord[0] = texcoord2f;
1592 m.pointer_texcoord3f[1] = svector3f;
1593 m.pointer_texcoord3f[2] = tvector3f;
1594 m.pointer_texcoord3f[3] = normal3f;
1595 m.tex[0] = R_GetTexture(bumptexture);
1596 m.tex[1] = R_GetTexture(basetexture);
1597 m.tex[2] = R_GetTexture(glosstexture);
1598 m.texcubemap[3] = R_GetTexture(lightcubemap);
1599 // TODO: support fog (after renderer is converted to texture fog)
1600 m.tex[4] = R_GetTexture(r_texture_white);
1601 m.texmatrix[3] = *matrix_modeltolight;
1603 GL_BlendFunc(GL_ONE, GL_ONE);
1604 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1607 // only add a feature to the permutation if that permutation exists
1608 // (otherwise it might end up not using a shader at all, which looks
1609 // worse than using less features)
1610 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1611 perm |= SHADERPERMUTATION_SPECULAR;
1612 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1613 // perm |= SHADERPERMUTATION_FOG;
1614 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1615 perm |= SHADERPERMUTATION_CUBEFILTER;
1616 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1617 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1618 prog = r_shadow_program_light[perm];
1619 qglUseProgramObjectARB(prog);CHECKGLERROR
1620 // TODO: support fog (after renderer is converted to texture fog)
1621 if (perm & SHADERPERMUTATION_FOG)
1623 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1625 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1626 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1627 if (perm & SHADERPERMUTATION_SPECULAR)
1629 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1630 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1632 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);CHECKGLERROR
1633 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1634 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1636 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1638 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1640 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1641 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1644 GL_LockArrays(firstvertex, numvertices);
1645 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1647 c_rt_lighttris += numtriangles;
1648 GL_LockArrays(0, 0);
1649 qglUseProgramObjectARB(0);
1650 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1651 qglBegin(GL_TRIANGLES);
1655 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1658 bumptexture = r_texture_blanknormalmap;
1660 glosstexture = r_texture_white;
1664 colorscale = ambientscale;
1665 // colorscale accounts for how much we multiply the brightness
1668 // mult is how many times the final pass of the lighting will be
1669 // performed to get more brightness than otherwise possible.
1671 // Limit mult to 64 for sanity sake.
1672 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1674 // 3 3D combine path (Geforce3, Radeon 8500)
1675 memset(&m, 0, sizeof(m));
1676 m.pointer_vertex = vertex3f;
1677 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1679 m.pointer_texcoord3f[0] = vertex3f;
1680 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1682 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1683 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1685 m.tex[1] = R_GetTexture(basetexture);
1686 m.pointer_texcoord[1] = texcoord2f;
1687 m.texcubemap[2] = R_GetTexture(lightcubemap);
1689 m.pointer_texcoord3f[2] = vertex3f;
1690 m.texmatrix[2] = *matrix_modeltolight;
1692 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1693 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1695 GL_BlendFunc(GL_ONE, GL_ONE);
1697 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1699 // 2 3D combine path (Geforce3, original Radeon)
1700 memset(&m, 0, sizeof(m));
1701 m.pointer_vertex = vertex3f;
1702 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1704 m.pointer_texcoord3f[0] = vertex3f;
1705 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1707 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1708 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1710 m.tex[1] = R_GetTexture(basetexture);
1711 m.pointer_texcoord[1] = texcoord2f;
1712 GL_BlendFunc(GL_ONE, GL_ONE);
1714 else if (r_textureunits.integer >= 4 && lightcubemap)
1716 // 4 2D combine path (Geforce3, Radeon 8500)
1717 memset(&m, 0, sizeof(m));
1718 m.pointer_vertex = vertex3f;
1719 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1721 m.pointer_texcoord3f[0] = vertex3f;
1722 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1724 m.pointer_texcoord[0] = varray_texcoord2f[0];
1725 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1727 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1729 m.pointer_texcoord3f[1] = vertex3f;
1730 m.texmatrix[1] = *matrix_modeltoattenuationz;
1732 m.pointer_texcoord[1] = varray_texcoord2f[1];
1733 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1735 m.tex[2] = R_GetTexture(basetexture);
1736 m.pointer_texcoord[2] = texcoord2f;
1739 m.texcubemap[3] = R_GetTexture(lightcubemap);
1741 m.pointer_texcoord3f[3] = vertex3f;
1742 m.texmatrix[3] = *matrix_modeltolight;
1744 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1745 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1748 GL_BlendFunc(GL_ONE, GL_ONE);
1750 else if (r_textureunits.integer >= 3 && !lightcubemap)
1752 // 3 2D combine path (Geforce3, original Radeon)
1753 memset(&m, 0, sizeof(m));
1754 m.pointer_vertex = vertex3f;
1755 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1757 m.pointer_texcoord3f[0] = vertex3f;
1758 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1760 m.pointer_texcoord[0] = varray_texcoord2f[0];
1761 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1763 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1765 m.pointer_texcoord3f[1] = vertex3f;
1766 m.texmatrix[1] = *matrix_modeltoattenuationz;
1768 m.pointer_texcoord[1] = varray_texcoord2f[1];
1769 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1771 m.tex[2] = R_GetTexture(basetexture);
1772 m.pointer_texcoord[2] = texcoord2f;
1773 GL_BlendFunc(GL_ONE, GL_ONE);
1777 // 2/2/2 2D combine path (any dot3 card)
1778 memset(&m, 0, sizeof(m));
1779 m.pointer_vertex = vertex3f;
1780 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1782 m.pointer_texcoord3f[0] = vertex3f;
1783 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1785 m.pointer_texcoord[0] = varray_texcoord2f[0];
1786 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1788 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1790 m.pointer_texcoord3f[1] = vertex3f;
1791 m.texmatrix[1] = *matrix_modeltoattenuationz;
1793 m.pointer_texcoord[1] = varray_texcoord2f[1];
1794 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1797 GL_ColorMask(0,0,0,1);
1798 GL_BlendFunc(GL_ONE, GL_ZERO);
1799 GL_LockArrays(firstvertex, numvertices);
1800 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1801 GL_LockArrays(0, 0);
1803 c_rt_lighttris += numtriangles;
1805 memset(&m, 0, sizeof(m));
1806 m.pointer_vertex = vertex3f;
1807 m.tex[0] = R_GetTexture(basetexture);
1808 m.pointer_texcoord[0] = texcoord2f;
1811 m.texcubemap[1] = R_GetTexture(lightcubemap);
1813 m.pointer_texcoord3f[1] = vertex3f;
1814 m.texmatrix[1] = *matrix_modeltolight;
1816 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1817 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1820 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1822 // this final code is shared
1824 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1825 VectorScale(lightcolor, colorscale, color2);
1826 GL_LockArrays(firstvertex, numvertices);
1827 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1829 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1830 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1832 c_rt_lighttris += numtriangles;
1834 GL_LockArrays(0, 0);
1839 colorscale = diffusescale;
1840 // colorscale accounts for how much we multiply the brightness
1843 // mult is how many times the final pass of the lighting will be
1844 // performed to get more brightness than otherwise possible.
1846 // Limit mult to 64 for sanity sake.
1847 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1849 // 3/2 3D combine path (Geforce3, Radeon 8500)
1850 memset(&m, 0, sizeof(m));
1851 m.pointer_vertex = vertex3f;
1852 m.tex[0] = R_GetTexture(bumptexture);
1853 m.texcombinergb[0] = GL_REPLACE;
1854 m.pointer_texcoord[0] = texcoord2f;
1855 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1856 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1857 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1858 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1859 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1861 m.pointer_texcoord3f[2] = vertex3f;
1862 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1864 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1865 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1868 GL_ColorMask(0,0,0,1);
1869 GL_BlendFunc(GL_ONE, GL_ZERO);
1870 GL_LockArrays(firstvertex, numvertices);
1871 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1872 GL_LockArrays(0, 0);
1874 c_rt_lighttris += numtriangles;
1876 memset(&m, 0, sizeof(m));
1877 m.pointer_vertex = vertex3f;
1878 m.tex[0] = R_GetTexture(basetexture);
1879 m.pointer_texcoord[0] = texcoord2f;
1882 m.texcubemap[1] = R_GetTexture(lightcubemap);
1884 m.pointer_texcoord3f[1] = vertex3f;
1885 m.texmatrix[1] = *matrix_modeltolight;
1887 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1888 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1891 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1893 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1895 // 1/2/2 3D combine path (original Radeon)
1896 memset(&m, 0, sizeof(m));
1897 m.pointer_vertex = vertex3f;
1898 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1900 m.pointer_texcoord3f[0] = vertex3f;
1901 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1903 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1904 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1907 GL_ColorMask(0,0,0,1);
1908 GL_BlendFunc(GL_ONE, GL_ZERO);
1909 GL_LockArrays(firstvertex, numvertices);
1910 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1911 GL_LockArrays(0, 0);
1913 c_rt_lighttris += numtriangles;
1915 memset(&m, 0, sizeof(m));
1916 m.pointer_vertex = vertex3f;
1917 m.tex[0] = R_GetTexture(bumptexture);
1918 m.texcombinergb[0] = GL_REPLACE;
1919 m.pointer_texcoord[0] = texcoord2f;
1920 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1921 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1922 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1923 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1925 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1926 GL_LockArrays(firstvertex, numvertices);
1927 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1928 GL_LockArrays(0, 0);
1930 c_rt_lighttris += numtriangles;
1932 memset(&m, 0, sizeof(m));
1933 m.pointer_vertex = vertex3f;
1934 m.tex[0] = R_GetTexture(basetexture);
1935 m.pointer_texcoord[0] = texcoord2f;
1938 m.texcubemap[1] = R_GetTexture(lightcubemap);
1940 m.pointer_texcoord3f[1] = vertex3f;
1941 m.texmatrix[1] = *matrix_modeltolight;
1943 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1944 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1947 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1949 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1951 // 2/2 3D combine path (original Radeon)
1952 memset(&m, 0, sizeof(m));
1953 m.pointer_vertex = vertex3f;
1954 m.tex[0] = R_GetTexture(bumptexture);
1955 m.texcombinergb[0] = GL_REPLACE;
1956 m.pointer_texcoord[0] = texcoord2f;
1957 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1958 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1959 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1960 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1962 GL_ColorMask(0,0,0,1);
1963 GL_BlendFunc(GL_ONE, GL_ZERO);
1964 GL_LockArrays(firstvertex, numvertices);
1965 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1966 GL_LockArrays(0, 0);
1968 c_rt_lighttris += numtriangles;
1970 memset(&m, 0, sizeof(m));
1971 m.pointer_vertex = vertex3f;
1972 m.tex[0] = R_GetTexture(basetexture);
1973 m.pointer_texcoord[0] = texcoord2f;
1974 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1976 m.pointer_texcoord3f[1] = vertex3f;
1977 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1979 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1980 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1982 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1984 else if (r_textureunits.integer >= 4)
1986 // 4/2 2D combine path (Geforce3, Radeon 8500)
1987 memset(&m, 0, sizeof(m));
1988 m.pointer_vertex = vertex3f;
1989 m.tex[0] = R_GetTexture(bumptexture);
1990 m.texcombinergb[0] = GL_REPLACE;
1991 m.pointer_texcoord[0] = texcoord2f;
1992 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1993 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1994 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1995 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1996 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1998 m.pointer_texcoord3f[2] = vertex3f;
1999 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2001 m.pointer_texcoord[2] = varray_texcoord2f[2];
2002 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2004 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2006 m.pointer_texcoord3f[3] = vertex3f;
2007 m.texmatrix[3] = *matrix_modeltoattenuationz;
2009 m.pointer_texcoord[3] = varray_texcoord2f[3];
2010 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2013 GL_ColorMask(0,0,0,1);
2014 GL_BlendFunc(GL_ONE, GL_ZERO);
2015 GL_LockArrays(firstvertex, numvertices);
2016 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2017 GL_LockArrays(0, 0);
2019 c_rt_lighttris += numtriangles;
2021 memset(&m, 0, sizeof(m));
2022 m.pointer_vertex = vertex3f;
2023 m.tex[0] = R_GetTexture(basetexture);
2024 m.pointer_texcoord[0] = texcoord2f;
2027 m.texcubemap[1] = R_GetTexture(lightcubemap);
2029 m.pointer_texcoord3f[1] = vertex3f;
2030 m.texmatrix[1] = *matrix_modeltolight;
2032 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2033 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2036 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2040 // 2/2/2 2D combine path (any dot3 card)
2041 memset(&m, 0, sizeof(m));
2042 m.pointer_vertex = vertex3f;
2043 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2045 m.pointer_texcoord3f[0] = vertex3f;
2046 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2048 m.pointer_texcoord[0] = varray_texcoord2f[0];
2049 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2051 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2053 m.pointer_texcoord3f[1] = vertex3f;
2054 m.texmatrix[1] = *matrix_modeltoattenuationz;
2056 m.pointer_texcoord[1] = varray_texcoord2f[1];
2057 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2060 GL_ColorMask(0,0,0,1);
2061 GL_BlendFunc(GL_ONE, GL_ZERO);
2062 GL_LockArrays(firstvertex, numvertices);
2063 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2064 GL_LockArrays(0, 0);
2066 c_rt_lighttris += numtriangles;
2068 memset(&m, 0, sizeof(m));
2069 m.pointer_vertex = vertex3f;
2070 m.tex[0] = R_GetTexture(bumptexture);
2071 m.texcombinergb[0] = GL_REPLACE;
2072 m.pointer_texcoord[0] = texcoord2f;
2073 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2074 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2075 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2076 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2078 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2079 GL_LockArrays(firstvertex, numvertices);
2080 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2081 GL_LockArrays(0, 0);
2083 c_rt_lighttris += numtriangles;
2085 memset(&m, 0, sizeof(m));
2086 m.pointer_vertex = vertex3f;
2087 m.tex[0] = R_GetTexture(basetexture);
2088 m.pointer_texcoord[0] = texcoord2f;
2091 m.texcubemap[1] = R_GetTexture(lightcubemap);
2093 m.pointer_texcoord3f[1] = vertex3f;
2094 m.texmatrix[1] = *matrix_modeltolight;
2096 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2097 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2100 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2102 // this final code is shared
2104 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2105 VectorScale(lightcolor, colorscale, color2);
2106 GL_LockArrays(firstvertex, numvertices);
2107 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2109 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2110 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2112 c_rt_lighttris += numtriangles;
2114 GL_LockArrays(0, 0);
2116 if (specularscale && glosstexture != r_texture_black)
2118 // FIXME: detect blendsquare!
2119 //if (gl_support_blendsquare)
2121 colorscale = specularscale;
2123 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2125 // 2/0/0/1/2 3D combine blendsquare path
2126 memset(&m, 0, sizeof(m));
2127 m.pointer_vertex = vertex3f;
2128 m.tex[0] = R_GetTexture(bumptexture);
2129 m.pointer_texcoord[0] = texcoord2f;
2130 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2131 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2132 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2133 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);
2135 GL_ColorMask(0,0,0,1);
2136 // this squares the result
2137 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2138 GL_LockArrays(firstvertex, numvertices);
2139 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2140 GL_LockArrays(0, 0);
2142 c_rt_lighttris += numtriangles;
2144 memset(&m, 0, sizeof(m));
2145 m.pointer_vertex = vertex3f;
2147 GL_LockArrays(firstvertex, numvertices);
2148 // square alpha in framebuffer a few times to make it shiny
2149 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2150 // these comments are a test run through this math for intensity 0.5
2151 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2152 // 0.25 * 0.25 = 0.0625 (this is another pass)
2153 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2154 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2156 c_rt_lighttris += numtriangles;
2157 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2159 c_rt_lighttris += numtriangles;
2160 GL_LockArrays(0, 0);
2162 memset(&m, 0, sizeof(m));
2163 m.pointer_vertex = vertex3f;
2164 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2166 m.pointer_texcoord3f[0] = vertex3f;
2167 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2169 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2170 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2173 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2174 GL_LockArrays(firstvertex, numvertices);
2175 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2176 GL_LockArrays(0, 0);
2178 c_rt_lighttris += numtriangles;
2180 memset(&m, 0, sizeof(m));
2181 m.pointer_vertex = vertex3f;
2182 m.tex[0] = R_GetTexture(glosstexture);
2183 m.pointer_texcoord[0] = texcoord2f;
2186 m.texcubemap[1] = R_GetTexture(lightcubemap);
2188 m.pointer_texcoord3f[1] = vertex3f;
2189 m.texmatrix[1] = *matrix_modeltolight;
2191 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2192 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2195 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2197 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2199 // 2/0/0/2 3D combine blendsquare path
2200 memset(&m, 0, sizeof(m));
2201 m.pointer_vertex = vertex3f;
2202 m.tex[0] = R_GetTexture(bumptexture);
2203 m.pointer_texcoord[0] = texcoord2f;
2204 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2205 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2206 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2207 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2209 GL_ColorMask(0,0,0,1);
2210 // this squares the result
2211 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2212 GL_LockArrays(firstvertex, numvertices);
2213 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2214 GL_LockArrays(0, 0);
2216 c_rt_lighttris += numtriangles;
2218 memset(&m, 0, sizeof(m));
2219 m.pointer_vertex = vertex3f;
2221 GL_LockArrays(firstvertex, numvertices);
2222 // square alpha in framebuffer a few times to make it shiny
2223 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2224 // these comments are a test run through this math for intensity 0.5
2225 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2226 // 0.25 * 0.25 = 0.0625 (this is another pass)
2227 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2228 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2230 c_rt_lighttris += numtriangles;
2231 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2233 c_rt_lighttris += numtriangles;
2234 GL_LockArrays(0, 0);
2236 memset(&m, 0, sizeof(m));
2237 m.pointer_vertex = vertex3f;
2238 m.tex[0] = R_GetTexture(glosstexture);
2239 m.pointer_texcoord[0] = texcoord2f;
2240 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2242 m.pointer_texcoord3f[1] = vertex3f;
2243 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2245 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2246 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2248 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2252 // 2/0/0/2/2 2D combine blendsquare path
2253 memset(&m, 0, sizeof(m));
2254 m.pointer_vertex = vertex3f;
2255 m.tex[0] = R_GetTexture(bumptexture);
2256 m.pointer_texcoord[0] = texcoord2f;
2257 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2258 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2259 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2260 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);
2262 GL_ColorMask(0,0,0,1);
2263 // this squares the result
2264 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2265 GL_LockArrays(firstvertex, numvertices);
2266 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2267 GL_LockArrays(0, 0);
2269 c_rt_lighttris += numtriangles;
2271 memset(&m, 0, sizeof(m));
2272 m.pointer_vertex = vertex3f;
2274 GL_LockArrays(firstvertex, numvertices);
2275 // square alpha in framebuffer a few times to make it shiny
2276 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2277 // these comments are a test run through this math for intensity 0.5
2278 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2279 // 0.25 * 0.25 = 0.0625 (this is another pass)
2280 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2281 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2283 c_rt_lighttris += numtriangles;
2284 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2286 c_rt_lighttris += numtriangles;
2287 GL_LockArrays(0, 0);
2289 memset(&m, 0, sizeof(m));
2290 m.pointer_vertex = vertex3f;
2291 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2293 m.pointer_texcoord3f[0] = vertex3f;
2294 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2296 m.pointer_texcoord[0] = varray_texcoord2f[0];
2297 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2299 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2301 m.pointer_texcoord3f[1] = vertex3f;
2302 m.texmatrix[1] = *matrix_modeltoattenuationz;
2304 m.pointer_texcoord[1] = varray_texcoord2f[1];
2305 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2308 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2309 GL_LockArrays(firstvertex, numvertices);
2310 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2311 GL_LockArrays(0, 0);
2313 c_rt_lighttris += numtriangles;
2315 memset(&m, 0, sizeof(m));
2316 m.pointer_vertex = vertex3f;
2317 m.tex[0] = R_GetTexture(glosstexture);
2318 m.pointer_texcoord[0] = texcoord2f;
2321 m.texcubemap[1] = R_GetTexture(lightcubemap);
2323 m.pointer_texcoord3f[1] = vertex3f;
2324 m.texmatrix[1] = *matrix_modeltolight;
2326 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2327 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2330 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2333 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2334 VectorScale(lightcolor, colorscale, color2);
2335 GL_LockArrays(firstvertex, numvertices);
2336 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2338 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2339 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2341 c_rt_lighttris += numtriangles;
2343 GL_LockArrays(0, 0);
2351 GL_BlendFunc(GL_ONE, GL_ONE);
2352 VectorScale(lightcolor, ambientscale, color2);
2353 memset(&m, 0, sizeof(m));
2354 m.pointer_vertex = vertex3f;
2355 m.tex[0] = R_GetTexture(basetexture);
2356 m.pointer_texcoord[0] = texcoord2f;
2357 if (r_textureunits.integer >= 2)
2360 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2362 m.pointer_texcoord3f[1] = vertex3f;
2363 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2365 m.pointer_texcoord[1] = varray_texcoord2f[1];
2366 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2368 if (r_textureunits.integer >= 3)
2370 // Geforce3/Radeon class but not using dot3
2371 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2373 m.pointer_texcoord3f[2] = vertex3f;
2374 m.texmatrix[2] = *matrix_modeltoattenuationz;
2376 m.pointer_texcoord[2] = varray_texcoord2f[2];
2377 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2381 if (r_textureunits.integer >= 3)
2382 m.pointer_color = NULL;
2384 m.pointer_color = varray_color4f;
2386 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2388 color[0] = bound(0, color2[0], 1);
2389 color[1] = bound(0, color2[1], 1);
2390 color[2] = bound(0, color2[2], 1);
2391 if (r_textureunits.integer >= 3)
2392 GL_Color(color[0], color[1], color[2], 1);
2393 else if (r_textureunits.integer >= 2)
2394 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2396 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2397 GL_LockArrays(firstvertex, numvertices);
2398 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2399 GL_LockArrays(0, 0);
2401 c_rt_lighttris += numtriangles;
2406 GL_BlendFunc(GL_ONE, GL_ONE);
2407 VectorScale(lightcolor, diffusescale, color2);
2408 memset(&m, 0, sizeof(m));
2409 m.pointer_vertex = vertex3f;
2410 m.pointer_color = varray_color4f;
2411 m.tex[0] = R_GetTexture(basetexture);
2412 m.pointer_texcoord[0] = texcoord2f;
2413 if (r_textureunits.integer >= 2)
2416 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2418 m.pointer_texcoord3f[1] = vertex3f;
2419 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2421 m.pointer_texcoord[1] = varray_texcoord2f[1];
2422 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2424 if (r_textureunits.integer >= 3)
2426 // Geforce3/Radeon class but not using dot3
2427 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2429 m.pointer_texcoord3f[2] = vertex3f;
2430 m.texmatrix[2] = *matrix_modeltoattenuationz;
2432 m.pointer_texcoord[2] = varray_texcoord2f[2];
2433 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2438 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2440 color[0] = bound(0, color2[0], 1);
2441 color[1] = bound(0, color2[1], 1);
2442 color[2] = bound(0, color2[2], 1);
2443 if (r_textureunits.integer >= 3)
2444 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2445 else if (r_textureunits.integer >= 2)
2446 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2448 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2449 GL_LockArrays(firstvertex, numvertices);
2450 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2451 GL_LockArrays(0, 0);
2453 c_rt_lighttris += numtriangles;
2459 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2463 R_RTLight_Uncompile(rtlight);
2464 memset(rtlight, 0, sizeof(*rtlight));
2466 VectorCopy(light->origin, rtlight->shadoworigin);
2467 VectorCopy(light->color, rtlight->color);
2468 rtlight->radius = light->radius;
2469 //rtlight->cullradius = rtlight->radius;
2470 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2471 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2472 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2473 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2474 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2475 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2476 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2477 rtlight->cubemapname[0] = 0;
2478 if (light->cubemapname[0])
2479 strcpy(rtlight->cubemapname, light->cubemapname);
2480 else if (light->cubemapnum > 0)
2481 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2482 rtlight->shadow = light->shadow;
2483 rtlight->corona = light->corona;
2484 rtlight->style = light->style;
2485 rtlight->isstatic = isstatic;
2486 rtlight->coronasizescale = light->coronasizescale;
2487 rtlight->ambientscale = light->ambientscale;
2488 rtlight->diffusescale = light->diffusescale;
2489 rtlight->specularscale = light->specularscale;
2490 rtlight->flags = light->flags;
2491 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2492 // ConcatScale won't work here because this needs to scale rotate and
2493 // translate, not just rotate
2494 scale = 1.0f / rtlight->radius;
2495 for (k = 0;k < 3;k++)
2496 for (j = 0;j < 4;j++)
2497 rtlight->matrix_worldtolight.m[k][j] *= scale;
2498 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2499 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2501 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2502 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2503 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2504 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2507 // compiles rtlight geometry
2508 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2509 void R_RTLight_Compile(rtlight_t *rtlight)
2511 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2512 entity_render_t *ent = r_refdef.worldentity;
2513 model_t *model = r_refdef.worldmodel;
2515 // compile the light
2516 rtlight->compiled = true;
2517 rtlight->static_numclusters = 0;
2518 rtlight->static_numclusterpvsbytes = 0;
2519 rtlight->static_clusterlist = NULL;
2520 rtlight->static_clusterpvs = NULL;
2521 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2522 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2523 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2524 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2525 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2526 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2528 if (model && model->GetLightInfo)
2530 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2531 r_shadow_compilingrtlight = rtlight;
2532 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2533 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2534 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);
2535 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2536 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2539 rtlight->static_numclusters = numclusters;
2540 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2541 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2542 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2544 if (model->DrawShadowVolume && rtlight->shadow)
2546 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2547 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2548 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2550 if (model->DrawLight)
2552 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2553 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);
2554 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2556 // switch back to rendering when DrawShadowVolume or DrawLight is called
2557 r_shadow_compilingrtlight = NULL;
2561 // use smallest available cullradius - box radius or light radius
2562 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2563 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2567 if (rtlight->static_meshchain_shadow)
2570 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2573 shadowtris += mesh->numtriangles;
2579 if (rtlight->static_meshchain_light)
2582 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2585 lighttris += mesh->numtriangles;
2589 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);
2592 void R_RTLight_Uncompile(rtlight_t *rtlight)
2594 if (rtlight->compiled)
2596 if (rtlight->static_meshchain_shadow)
2597 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2598 rtlight->static_meshchain_shadow = NULL;
2599 if (rtlight->static_meshchain_light)
2600 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2601 rtlight->static_meshchain_light = NULL;
2602 if (rtlight->static_clusterlist)
2603 Mem_Free(rtlight->static_clusterlist);
2604 rtlight->static_clusterlist = NULL;
2605 if (rtlight->static_clusterpvs)
2606 Mem_Free(rtlight->static_clusterpvs);
2607 rtlight->static_clusterpvs = NULL;
2608 rtlight->static_numclusters = 0;
2609 rtlight->static_numclusterpvsbytes = 0;
2610 rtlight->compiled = false;
2614 void R_Shadow_UncompileWorldLights(void)
2617 for (light = r_shadow_worldlightchain;light;light = light->next)
2618 R_RTLight_Uncompile(&light->rtlight);
2621 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2623 int i, shadow, usestencil;
2624 entity_render_t *ent;
2626 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2627 rtexture_t *cubemaptexture;
2628 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2629 int numclusters, numsurfaces;
2630 int *clusterlist, *surfacelist;
2632 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2636 // skip lights that don't light (corona only lights)
2637 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2640 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2641 VectorScale(rtlight->color, f, lightcolor);
2642 if (VectorLength2(lightcolor) < 0.01)
2645 if (rtlight->selected)
2647 f = 2 + sin(realtime * M_PI * 4.0);
2648 VectorScale(lightcolor, f, lightcolor);
2652 // loading is done before visibility checks because loading should happen
2653 // all at once at the start of a level, not when it stalls gameplay.
2654 // (especially important to benchmarks)
2655 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2656 R_RTLight_Compile(rtlight);
2657 if (rtlight->cubemapname[0])
2658 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2660 cubemaptexture = NULL;
2662 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2663 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2664 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2665 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2666 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2667 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2668 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2675 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2677 // compiled light, world available and can receive realtime lighting
2678 // retrieve cluster information
2679 numclusters = rtlight->static_numclusters;
2680 clusterlist = rtlight->static_clusterlist;
2681 clusterpvs = rtlight->static_clusterpvs;
2682 VectorCopy(rtlight->cullmins, cullmins);
2683 VectorCopy(rtlight->cullmaxs, cullmaxs);
2685 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2687 // dynamic light, world available and can receive realtime lighting
2688 // if the light box is offscreen, skip it right away
2689 if (R_CullBox(cullmins, cullmaxs))
2691 // calculate lit surfaces and clusters
2692 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2693 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2694 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);
2695 clusterlist = r_shadow_buffer_clusterlist;
2696 clusterpvs = r_shadow_buffer_clusterpvs;
2697 surfacelist = r_shadow_buffer_surfacelist;
2699 // if the reduced cluster bounds are offscreen, skip it
2700 if (R_CullBox(cullmins, cullmaxs))
2702 // check if light is illuminating any visible clusters
2705 for (i = 0;i < numclusters;i++)
2706 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2708 if (i == numclusters)
2711 // set up a scissor rectangle for this light
2712 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2715 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2718 if (shadow && (gl_stencil || visiblevolumes))
2720 if (!visiblevolumes)
2722 R_Shadow_Stage_ShadowVolumes();
2725 ent = r_refdef.worldentity;
2726 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2728 memset(&m, 0, sizeof(m));
2729 R_Mesh_Matrix(&ent->matrix);
2730 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2732 m.pointer_vertex = mesh->vertex3f;
2734 GL_LockArrays(0, mesh->numverts);
2735 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2737 // increment stencil if backface is behind depthbuffer
2738 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2739 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2740 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2741 c_rtcached_shadowmeshes++;
2742 c_rtcached_shadowtris += mesh->numtriangles;
2743 // decrement stencil if frontface is behind depthbuffer
2744 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2745 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2747 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2748 c_rtcached_shadowmeshes++;
2749 c_rtcached_shadowtris += mesh->numtriangles;
2750 GL_LockArrays(0, 0);
2753 else if (numsurfaces)
2755 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2756 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2758 if (r_drawentities.integer)
2760 for (i = 0;i < r_refdef.numentities;i++)
2762 ent = r_refdef.entities[i];
2764 if (r_shadow_cull.integer)
2766 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2768 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2771 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2773 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2774 // light emitting entities should not cast their own shadow
2775 if (VectorLength2(relativelightorigin) < 0.1)
2777 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2778 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2779 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2780 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2781 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2782 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2783 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2788 if (!visiblevolumes)
2790 R_Shadow_Stage_Light(usestencil);
2792 ent = r_refdef.worldentity;
2793 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2795 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2796 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2797 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2798 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2799 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2800 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2801 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2802 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2803 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2805 R_Mesh_Matrix(&ent->matrix);
2806 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2807 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
2810 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2812 if (r_drawentities.integer)
2814 for (i = 0;i < r_refdef.numentities;i++)
2816 ent = r_refdef.entities[i];
2817 // can't draw transparent entity lighting here because
2818 // transparent meshes are deferred for later
2819 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)
2821 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2822 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2823 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2824 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2825 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2826 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2827 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2828 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2829 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);
2836 void R_ShadowVolumeLighting(int visiblevolumes)
2842 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2843 R_Shadow_EditLights_Reload_f();
2847 memset(&m, 0, sizeof(m));
2850 GL_BlendFunc(GL_ONE, GL_ONE);
2851 GL_DepthMask(false);
2852 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2853 qglDisable(GL_CULL_FACE);
2854 GL_Color(0.0, 0.0125, 0.1, 1);
2857 R_Shadow_Stage_Begin();
2858 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2859 if (r_shadow_debuglight.integer >= 0)
2861 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2862 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2863 R_DrawRTLight(&light->rtlight, visiblevolumes);
2866 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2867 if (light->flags & flag)
2868 R_DrawRTLight(&light->rtlight, visiblevolumes);
2870 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2871 R_DrawRTLight(&light->rtlight, visiblevolumes);
2875 qglEnable(GL_CULL_FACE);
2876 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2879 R_Shadow_Stage_End();
2882 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2883 typedef struct suffixinfo_s
2886 qboolean flipx, flipy, flipdiagonal;
2889 static suffixinfo_t suffix[3][6] =
2892 {"px", false, false, false},
2893 {"nx", false, false, false},
2894 {"py", false, false, false},
2895 {"ny", false, false, false},
2896 {"pz", false, false, false},
2897 {"nz", false, false, false}
2900 {"posx", false, false, false},
2901 {"negx", false, false, false},
2902 {"posy", false, false, false},
2903 {"negy", false, false, false},
2904 {"posz", false, false, false},
2905 {"negz", false, false, false}
2908 {"rt", true, false, true},
2909 {"lf", false, true, true},
2910 {"ft", true, true, false},
2911 {"bk", false, false, false},
2912 {"up", true, false, true},