3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankwhitecubetexture;
159 // lights are reloaded when this changes
160 char r_shadow_mapname[MAX_QPATH];
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
165 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
166 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
167 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
168 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
169 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
170 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
171 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
172 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
173 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
174 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
175 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
176 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
177 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
178 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
179 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
180 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
181 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
182 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
183 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
184 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
185 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
186 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
187 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
188 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
189 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
190 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
191 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
192 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
193 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
194 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
195 cvar_t r_editlights = {0, "r_editlights", "0"};
196 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
197 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
198 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
199 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
200 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
201 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
202 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
204 float r_shadow_attenpower, r_shadow_attenscale;
206 rtlight_t *r_shadow_compilingrtlight;
207 dlight_t *r_shadow_worldlightchain;
208 dlight_t *r_shadow_selectedlight;
209 dlight_t r_shadow_bufferlight;
210 vec3_t r_editlights_cursorlocation;
212 rtexture_t *lighttextures[5];
214 extern int con_vislines;
216 typedef struct cubemapinfo_s
223 #define MAX_CUBEMAPS 256
224 static int numcubemaps;
225 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
227 #define SHADERPERMUTATION_SPECULAR (1<<0)
228 #define SHADERPERMUTATION_FOG (1<<1)
229 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
230 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
231 #define SHADERPERMUTATION_COUNT (1<<4)
233 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
235 void R_Shadow_UncompileWorldLights(void);
236 void R_Shadow_ClearWorldLights(void);
237 void R_Shadow_SaveWorldLights(void);
238 void R_Shadow_LoadWorldLights(void);
239 void R_Shadow_LoadLightsFile(void);
240 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
241 void R_Shadow_EditLights_Reload_f(void);
242 void R_Shadow_ValidateCvars(void);
243 static void R_Shadow_MakeTextures(void);
244 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
246 const char *builtinshader_light_vert =
247 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
248 "// written by Forest 'LordHavoc' Hale\n"
250 "uniform vec3 LightPosition;\n"
252 "varying vec2 TexCoord;\n"
253 "varying vec3 CubeVector;\n"
254 "varying vec3 LightVector;\n"
256 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
257 "uniform vec3 EyePosition;\n"
258 "varying vec3 EyeVector;\n"
261 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
265 " // copy the surface texcoord\n"
266 " TexCoord = gl_MultiTexCoord0.st;\n"
268 " // transform vertex position into light attenuation/cubemap space\n"
269 " // (-1 to +1 across the light box)\n"
270 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
272 " // transform unnormalized light direction into tangent space\n"
273 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
274 " // normalize it per pixel)\n"
275 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
276 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
277 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
278 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
280 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
281 " // transform unnormalized eye direction into tangent space\n"
282 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
283 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
284 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
285 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
288 " // transform vertex to camera space, using ftransform to match non-VS\n"
290 " gl_Position = ftransform();\n"
294 const char *builtinshader_light_frag =
295 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
296 "// written by Forest 'LordHavoc' Hale\n"
298 "uniform vec3 LightColor;\n"
300 "#ifdef USEOFFSETMAPPING\n"
301 "uniform float OffsetMapping_Scale;\n"
302 "uniform float OffsetMapping_Bias;\n"
304 "#ifdef USESPECULAR\n"
305 "uniform float SpecularPower;\n"
308 "uniform float FogRangeRecip;\n"
310 "uniform float AmbientScale;\n"
311 "uniform float DiffuseScale;\n"
312 "#ifdef USESPECULAR\n"
313 "uniform float SpecularScale;\n"
316 "uniform sampler2D Texture_Normal;\n"
317 "uniform sampler2D Texture_Color;\n"
318 "#ifdef USESPECULAR\n"
319 "uniform sampler2D Texture_Gloss;\n"
321 "#ifdef USECUBEFILTER\n"
322 "uniform samplerCube Texture_Cube;\n"
325 "uniform sampler2D Texture_FogMask;\n"
328 "varying vec2 TexCoord;\n"
329 "varying vec3 CubeVector;\n"
330 "varying vec3 LightVector;\n"
331 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
332 "varying vec3 EyeVector;\n"
339 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
340 " // center and sharp falloff at the edge, this is about the most efficient\n"
341 " // we can get away with as far as providing illumination.\n"
343 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
344 " // provide significant illumination, large = slow = pain.\n"
345 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
349 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
352 "#ifdef USEOFFSETMAPPING\n"
353 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
354 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
355 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
356 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
357 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
358 "#define TexCoord TexCoordOffset\n"
361 " // get the texels - with a blendmap we'd need to blend multiple here\n"
362 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
363 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
364 "#ifdef USESPECULAR\n"
365 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
368 " // calculate shading\n"
369 " vec3 diffusenormal = normalize(LightVector);\n"
370 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
371 "#ifdef USESPECULAR\n"
372 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
375 "#ifdef USECUBEFILTER\n"
376 " // apply light cubemap filter\n"
377 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
380 " // calculate fragment color\n"
381 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
385 void r_shadow_start(void)
388 // allocate vertex processing arrays
390 r_shadow_normalcubetexture = NULL;
391 r_shadow_attenuation2dtexture = NULL;
392 r_shadow_attenuation3dtexture = NULL;
393 r_shadow_blankwhitecubetexture = NULL;
394 r_shadow_texturepool = NULL;
395 r_shadow_filters_texturepool = NULL;
396 R_Shadow_ValidateCvars();
397 R_Shadow_MakeTextures();
398 maxshadowelements = 0;
399 shadowelements = NULL;
407 shadowmarklist = NULL;
409 r_shadow_buffer_numclusterpvsbytes = 0;
410 r_shadow_buffer_clusterpvs = NULL;
411 r_shadow_buffer_clusterlist = NULL;
412 r_shadow_buffer_numsurfacepvsbytes = 0;
413 r_shadow_buffer_surfacepvs = NULL;
414 r_shadow_buffer_surfacelist = NULL;
415 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
416 r_shadow_program_light[i] = 0;
417 if (gl_support_fragment_shader)
419 char *vertstring, *fragstring;
420 int vertstrings_count;
421 int fragstrings_count;
422 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
423 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
424 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
425 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
426 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
428 vertstrings_count = 0;
429 fragstrings_count = 0;
430 if (i & SHADERPERMUTATION_SPECULAR)
432 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
433 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
435 if (i & SHADERPERMUTATION_FOG)
437 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
438 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
440 if (i & SHADERPERMUTATION_CUBEFILTER)
442 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
443 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
445 if (i & SHADERPERMUTATION_OFFSETMAPPING)
447 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
448 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
450 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
451 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
452 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
453 if (!r_shadow_program_light[i])
455 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
458 qglUseProgramObjectARB(r_shadow_program_light[i]);
459 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
460 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
461 if (i & SHADERPERMUTATION_SPECULAR)
463 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
465 if (i & SHADERPERMUTATION_CUBEFILTER)
467 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
469 if (i & SHADERPERMUTATION_FOG)
471 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
474 qglUseProgramObjectARB(0);
476 Mem_Free(fragstring);
478 Mem_Free(vertstring);
482 void r_shadow_shutdown(void)
485 R_Shadow_UncompileWorldLights();
486 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
488 if (r_shadow_program_light[i])
490 GL_Backend_FreeProgram(r_shadow_program_light[i]);
491 r_shadow_program_light[i] = 0;
495 r_shadow_normalcubetexture = NULL;
496 r_shadow_attenuation2dtexture = NULL;
497 r_shadow_attenuation3dtexture = NULL;
498 r_shadow_blankwhitecubetexture = NULL;
499 R_FreeTexturePool(&r_shadow_texturepool);
500 R_FreeTexturePool(&r_shadow_filters_texturepool);
501 maxshadowelements = 0;
503 Mem_Free(shadowelements);
504 shadowelements = NULL;
507 Mem_Free(vertexupdate);
510 Mem_Free(vertexremap);
516 Mem_Free(shadowmark);
519 Mem_Free(shadowmarklist);
520 shadowmarklist = NULL;
522 r_shadow_buffer_numclusterpvsbytes = 0;
523 if (r_shadow_buffer_clusterpvs)
524 Mem_Free(r_shadow_buffer_clusterpvs);
525 r_shadow_buffer_clusterpvs = NULL;
526 if (r_shadow_buffer_clusterlist)
527 Mem_Free(r_shadow_buffer_clusterlist);
528 r_shadow_buffer_clusterlist = NULL;
529 r_shadow_buffer_numsurfacepvsbytes = 0;
530 if (r_shadow_buffer_surfacepvs)
531 Mem_Free(r_shadow_buffer_surfacepvs);
532 r_shadow_buffer_surfacepvs = NULL;
533 if (r_shadow_buffer_surfacelist)
534 Mem_Free(r_shadow_buffer_surfacelist);
535 r_shadow_buffer_surfacelist = NULL;
538 void r_shadow_newmap(void)
542 void R_Shadow_Help_f(void)
545 "Documentation on r_shadow system:\n"
547 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
548 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
549 "r_shadow_debuglight : render only this light number (-1 = all)\n"
550 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
551 "r_shadow_gloss2intensity : brightness of forced gloss\n"
552 "r_shadow_glossintensity : brightness of textured gloss\n"
553 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
554 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
555 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
556 "r_shadow_portallight : use portal visibility for static light precomputation\n"
557 "r_shadow_projectdistance : shadow volume projection distance\n"
558 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
559 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
560 "r_shadow_realtime_world : use high quality world lighting mode\n"
561 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
562 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
563 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
564 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
565 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
566 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
567 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
568 "r_shadow_scissor : use scissor optimization\n"
569 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
570 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
571 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
572 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
573 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
575 "r_shadow_help : this help\n"
579 void R_Shadow_Init(void)
581 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
582 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
583 Cvar_RegisterVariable(&r_shadow_cull);
584 Cvar_RegisterVariable(&r_shadow_debuglight);
585 Cvar_RegisterVariable(&r_shadow_gloss);
586 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
587 Cvar_RegisterVariable(&r_shadow_glossintensity);
588 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
589 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
590 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
591 Cvar_RegisterVariable(&r_shadow_portallight);
592 Cvar_RegisterVariable(&r_shadow_projectdistance);
593 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
594 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
595 Cvar_RegisterVariable(&r_shadow_realtime_world);
596 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
597 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
598 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
599 Cvar_RegisterVariable(&r_shadow_scissor);
600 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
601 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
602 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
603 Cvar_RegisterVariable(&r_shadow_staticworldlights);
604 Cvar_RegisterVariable(&r_shadow_texture3d);
605 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
606 Cvar_RegisterVariable(&r_shadow_glsl);
607 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
608 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
609 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
610 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
611 if (gamemode == GAME_TENEBRAE)
613 Cvar_SetValue("r_shadow_gloss", 2);
614 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
616 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
617 R_Shadow_EditLights_Init();
618 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
619 r_shadow_worldlightchain = NULL;
620 maxshadowelements = 0;
621 shadowelements = NULL;
629 shadowmarklist = NULL;
631 r_shadow_buffer_numclusterpvsbytes = 0;
632 r_shadow_buffer_clusterpvs = NULL;
633 r_shadow_buffer_clusterlist = NULL;
634 r_shadow_buffer_numsurfacepvsbytes = 0;
635 r_shadow_buffer_surfacepvs = NULL;
636 r_shadow_buffer_surfacelist = NULL;
637 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
640 matrix4x4_t matrix_attenuationxyz =
643 {0.5, 0.0, 0.0, 0.5},
644 {0.0, 0.5, 0.0, 0.5},
645 {0.0, 0.0, 0.5, 0.5},
650 matrix4x4_t matrix_attenuationz =
653 {0.0, 0.0, 0.5, 0.5},
654 {0.0, 0.0, 0.0, 0.5},
655 {0.0, 0.0, 0.0, 0.5},
660 int *R_Shadow_ResizeShadowElements(int numtris)
662 // make sure shadowelements is big enough for this volume
663 if (maxshadowelements < numtris * 24)
665 maxshadowelements = numtris * 24;
667 Mem_Free(shadowelements);
668 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
670 return shadowelements;
673 void R_Shadow_EnlargeClusterSurfaceBuffer(int numclusters, int numsurfaces)
675 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
676 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
677 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
679 if (r_shadow_buffer_clusterpvs)
680 Mem_Free(r_shadow_buffer_clusterpvs);
681 if (r_shadow_buffer_clusterlist)
682 Mem_Free(r_shadow_buffer_clusterlist);
683 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
684 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
685 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
687 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
689 if (r_shadow_buffer_surfacepvs)
690 Mem_Free(r_shadow_buffer_surfacepvs);
691 if (r_shadow_buffer_surfacelist)
692 Mem_Free(r_shadow_buffer_surfacelist);
693 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
694 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
695 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
699 void R_Shadow_PrepareShadowMark(int numtris)
701 // make sure shadowmark is big enough for this volume
702 if (maxshadowmark < numtris)
704 maxshadowmark = numtris;
706 Mem_Free(shadowmark);
708 Mem_Free(shadowmarklist);
709 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
710 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
714 // if shadowmarkcount wrapped we clear the array and adjust accordingly
715 if (shadowmarkcount == 0)
718 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
723 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
726 int outtriangles = 0, outvertices = 0;
730 if (maxvertexupdate < innumvertices)
732 maxvertexupdate = innumvertices;
734 Mem_Free(vertexupdate);
736 Mem_Free(vertexremap);
737 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
738 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
742 if (vertexupdatenum == 0)
745 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
746 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
749 for (i = 0;i < numshadowmarktris;i++)
750 shadowmark[shadowmarktris[i]] = shadowmarkcount;
752 for (i = 0;i < numshadowmarktris;i++)
754 element = inelement3i + shadowmarktris[i] * 3;
755 // make sure the vertices are created
756 for (j = 0;j < 3;j++)
758 if (vertexupdate[element[j]] != vertexupdatenum)
760 float ratio, direction[3];
761 vertexupdate[element[j]] = vertexupdatenum;
762 vertexremap[element[j]] = outvertices;
763 vertex = invertex3f + element[j] * 3;
764 // project one copy of the vertex to the sphere radius of the light
765 // (FIXME: would projecting it to the light box be better?)
766 VectorSubtract(vertex, projectorigin, direction);
767 ratio = projectdistance / VectorLength(direction);
768 VectorCopy(vertex, outvertex3f);
769 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
776 for (i = 0;i < numshadowmarktris;i++)
778 int remappedelement[3];
780 const int *neighbortriangle;
782 markindex = shadowmarktris[i] * 3;
783 element = inelement3i + markindex;
784 neighbortriangle = inneighbor3i + markindex;
785 // output the front and back triangles
786 outelement3i[0] = vertexremap[element[0]];
787 outelement3i[1] = vertexremap[element[1]];
788 outelement3i[2] = vertexremap[element[2]];
789 outelement3i[3] = vertexremap[element[2]] + 1;
790 outelement3i[4] = vertexremap[element[1]] + 1;
791 outelement3i[5] = vertexremap[element[0]] + 1;
795 // output the sides (facing outward from this triangle)
796 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
798 remappedelement[0] = vertexremap[element[0]];
799 remappedelement[1] = vertexremap[element[1]];
800 outelement3i[0] = remappedelement[1];
801 outelement3i[1] = remappedelement[0];
802 outelement3i[2] = remappedelement[0] + 1;
803 outelement3i[3] = remappedelement[1];
804 outelement3i[4] = remappedelement[0] + 1;
805 outelement3i[5] = remappedelement[1] + 1;
810 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
812 remappedelement[1] = vertexremap[element[1]];
813 remappedelement[2] = vertexremap[element[2]];
814 outelement3i[0] = remappedelement[2];
815 outelement3i[1] = remappedelement[1];
816 outelement3i[2] = remappedelement[1] + 1;
817 outelement3i[3] = remappedelement[2];
818 outelement3i[4] = remappedelement[1] + 1;
819 outelement3i[5] = remappedelement[2] + 1;
824 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
826 remappedelement[0] = vertexremap[element[0]];
827 remappedelement[2] = vertexremap[element[2]];
828 outelement3i[0] = remappedelement[0];
829 outelement3i[1] = remappedelement[2];
830 outelement3i[2] = remappedelement[2] + 1;
831 outelement3i[3] = remappedelement[0];
832 outelement3i[4] = remappedelement[2] + 1;
833 outelement3i[5] = remappedelement[0] + 1;
840 *outnumvertices = outvertices;
844 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
847 if (projectdistance < 0.1)
849 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
852 if (!numverts || !nummarktris)
854 // make sure shadowelements is big enough for this volume
855 if (maxshadowelements < nummarktris * 24)
856 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
857 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
858 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
861 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
866 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
868 tend = firsttriangle + numtris;
869 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
870 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
871 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
873 // surface box entirely inside light box, no box cull
874 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
875 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
876 shadowmarklist[numshadowmark++] = t;
880 // surface box not entirely inside light box, cull each triangle
881 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
883 v[0] = invertex3f + e[0] * 3;
884 v[1] = invertex3f + e[1] * 3;
885 v[2] = invertex3f + e[2] * 3;
886 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
887 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
888 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
889 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
890 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
891 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
892 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
893 shadowmarklist[numshadowmark++] = t;
898 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
901 if (r_shadow_compilingrtlight)
903 // if we're compiling an rtlight, capture the mesh
904 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
907 memset(&m, 0, sizeof(m));
908 m.pointer_vertex = vertex3f;
910 GL_LockArrays(0, numvertices);
911 if (r_shadowstage == SHADOWSTAGE_STENCIL)
913 // increment stencil if backface is behind depthbuffer
914 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
915 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
916 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
918 c_rt_shadowtris += numtriangles;
919 // decrement stencil if frontface is behind depthbuffer
920 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
921 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
923 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
925 c_rt_shadowtris += numtriangles;
929 static void R_Shadow_MakeTextures(void)
931 int x, y, z, d, side;
932 float v[3], s, t, intensity;
934 R_FreeTexturePool(&r_shadow_texturepool);
935 r_shadow_texturepool = R_AllocTexturePool();
936 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
937 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
939 #define ATTEN2DSIZE 64
940 #define ATTEN3DSIZE 32
941 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
942 r_shadow_blankwhitecubetexture = NULL;
943 r_shadow_normalcubetexture = NULL;
944 if (gl_texturecubemap)
946 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
947 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
948 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
949 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
950 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
951 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
952 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
953 for (side = 0;side < 6;side++)
955 for (y = 0;y < NORMSIZE;y++)
957 for (x = 0;x < NORMSIZE;x++)
959 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
960 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
994 intensity = 127.0f / sqrt(DotProduct(v, v));
995 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
996 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
997 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
998 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1002 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1004 for (y = 0;y < ATTEN2DSIZE;y++)
1006 for (x = 0;x < ATTEN2DSIZE;x++)
1008 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1009 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1011 intensity = 1.0f - sqrt(DotProduct(v, v));
1013 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1014 d = bound(0, intensity, 255);
1015 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1016 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1017 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1018 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1021 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1022 if (r_shadow_texture3d.integer)
1024 for (z = 0;z < ATTEN3DSIZE;z++)
1026 for (y = 0;y < ATTEN3DSIZE;y++)
1028 for (x = 0;x < ATTEN3DSIZE;x++)
1030 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1031 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1032 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1033 intensity = 1.0f - sqrt(DotProduct(v, v));
1035 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1036 d = bound(0, intensity, 255);
1037 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1038 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1039 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1040 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1044 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1049 void R_Shadow_ValidateCvars(void)
1051 if (r_shadow_texture3d.integer && !gl_texture3d)
1052 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1053 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1054 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1057 void R_Shadow_Stage_Begin(void)
1061 R_Shadow_ValidateCvars();
1063 if (!r_shadow_attenuation2dtexture
1064 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1065 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1066 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1067 R_Shadow_MakeTextures();
1069 memset(&m, 0, sizeof(m));
1070 GL_BlendFunc(GL_ONE, GL_ZERO);
1071 GL_DepthMask(false);
1074 GL_Color(0, 0, 0, 1);
1075 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1076 qglEnable(GL_CULL_FACE);
1077 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1078 r_shadowstage = SHADOWSTAGE_NONE;
1081 void R_Shadow_Stage_ShadowVolumes(void)
1084 memset(&m, 0, sizeof(m));
1086 GL_Color(1, 1, 1, 1);
1087 GL_ColorMask(0, 0, 0, 0);
1088 GL_BlendFunc(GL_ONE, GL_ZERO);
1089 GL_DepthMask(false);
1091 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1092 //if (r_shadow_shadow_polygonoffset.value != 0)
1094 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1095 // qglEnable(GL_POLYGON_OFFSET_FILL);
1098 // qglDisable(GL_POLYGON_OFFSET_FILL);
1099 qglDepthFunc(GL_LESS);
1100 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1101 qglEnable(GL_STENCIL_TEST);
1102 qglStencilFunc(GL_ALWAYS, 128, ~0);
1103 if (gl_ext_stenciltwoside.integer)
1105 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1106 qglDisable(GL_CULL_FACE);
1107 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1108 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1110 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1111 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1113 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1117 r_shadowstage = SHADOWSTAGE_STENCIL;
1118 qglEnable(GL_CULL_FACE);
1120 // this is changed by every shadow render so its value here is unimportant
1121 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1123 GL_Clear(GL_STENCIL_BUFFER_BIT);
1125 // LordHavoc note: many shadow volumes reside entirely inside the world
1126 // (that is to say they are entirely bounded by their lit surfaces),
1127 // which can be optimized by handling things as an inverted light volume,
1128 // with the shadow boundaries of the world being simulated by an altered
1129 // (129) bias to stencil clearing on such lights
1130 // FIXME: generate inverted light volumes for use as shadow volumes and
1131 // optimize for them as noted above
1134 void R_Shadow_Stage_Light(int shadowtest)
1137 memset(&m, 0, sizeof(m));
1139 GL_BlendFunc(GL_ONE, GL_ONE);
1140 GL_DepthMask(false);
1142 qglPolygonOffset(0, 0);
1143 //qglDisable(GL_POLYGON_OFFSET_FILL);
1144 GL_Color(1, 1, 1, 1);
1145 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1146 qglDepthFunc(GL_EQUAL);
1147 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1148 qglEnable(GL_CULL_FACE);
1150 qglEnable(GL_STENCIL_TEST);
1152 qglDisable(GL_STENCIL_TEST);
1153 if (gl_support_stenciltwoside)
1154 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1156 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1157 // only draw light where this geometry was already rendered AND the
1158 // stencil is 128 (values other than this mean shadow)
1159 qglStencilFunc(GL_EQUAL, 128, ~0);
1160 r_shadowstage = SHADOWSTAGE_LIGHT;
1164 void R_Shadow_Stage_End(void)
1167 memset(&m, 0, sizeof(m));
1169 GL_BlendFunc(GL_ONE, GL_ZERO);
1172 qglPolygonOffset(0, 0);
1173 //qglDisable(GL_POLYGON_OFFSET_FILL);
1174 GL_Color(1, 1, 1, 1);
1175 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1176 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1177 qglDepthFunc(GL_LEQUAL);
1178 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1179 qglDisable(GL_STENCIL_TEST);
1180 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1181 if (gl_support_stenciltwoside)
1182 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1184 qglStencilFunc(GL_ALWAYS, 128, ~0);
1185 r_shadowstage = SHADOWSTAGE_NONE;
1188 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1190 int i, ix1, iy1, ix2, iy2;
1191 float x1, y1, x2, y2, x, y, f;
1192 vec3_t smins, smaxs;
1194 if (!r_shadow_scissor.integer)
1196 // if view is inside the box, just say yes it's visible
1197 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1199 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1202 for (i = 0;i < 3;i++)
1204 if (r_viewforward[i] >= 0)
1215 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1216 if (DotProduct(r_viewforward, v2) <= f)
1218 // entirely behind nearclip plane
1221 if (DotProduct(r_viewforward, v) >= f)
1223 // entirely infront of nearclip plane
1224 x1 = y1 = x2 = y2 = 0;
1225 for (i = 0;i < 8;i++)
1227 v[0] = (i & 1) ? mins[0] : maxs[0];
1228 v[1] = (i & 2) ? mins[1] : maxs[1];
1229 v[2] = (i & 4) ? mins[2] : maxs[2];
1231 GL_TransformToScreen(v, v2);
1232 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1251 // clipped by nearclip plane
1252 // this is nasty and crude...
1253 // create viewspace bbox
1254 for (i = 0;i < 8;i++)
1256 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1257 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1258 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1259 v2[0] = -DotProduct(v, r_viewleft);
1260 v2[1] = DotProduct(v, r_viewup);
1261 v2[2] = DotProduct(v, r_viewforward);
1264 if (smins[0] > v2[0]) smins[0] = v2[0];
1265 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1266 if (smins[1] > v2[1]) smins[1] = v2[1];
1267 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1268 if (smins[2] > v2[2]) smins[2] = v2[2];
1269 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1273 smins[0] = smaxs[0] = v2[0];
1274 smins[1] = smaxs[1] = v2[1];
1275 smins[2] = smaxs[2] = v2[2];
1278 // now we have a bbox in viewspace
1279 // clip it to the view plane
1282 // return true if that culled the box
1283 if (smins[2] >= smaxs[2])
1285 // ok some of it is infront of the view, transform each corner back to
1286 // worldspace and then to screenspace and make screen rect
1287 // initialize these variables just to avoid compiler warnings
1288 x1 = y1 = x2 = y2 = 0;
1289 for (i = 0;i < 8;i++)
1291 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1292 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1293 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1294 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1295 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1296 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1298 GL_TransformToScreen(v, v2);
1299 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1316 // this code doesn't handle boxes with any points behind view properly
1317 x1 = 1000;x2 = -1000;
1318 y1 = 1000;y2 = -1000;
1319 for (i = 0;i < 8;i++)
1321 v[0] = (i & 1) ? mins[0] : maxs[0];
1322 v[1] = (i & 2) ? mins[1] : maxs[1];
1323 v[2] = (i & 4) ? mins[2] : maxs[2];
1325 GL_TransformToScreen(v, v2);
1326 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1344 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1345 if (ix1 < r_view_x) ix1 = r_view_x;
1346 if (iy1 < r_view_y) iy1 = r_view_y;
1347 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1348 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1349 if (ix2 <= ix1 || iy2 <= iy1)
1351 // set up the scissor rectangle
1352 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1353 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1354 //qglEnable(GL_SCISSOR_TEST);
1359 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1361 float *color4f = varray_color4f;
1362 float dist, dot, intensity, v[3], n[3];
1363 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1365 Matrix4x4_Transform(m, vertex3f, v);
1366 if ((dist = DotProduct(v, v)) < 1)
1368 Matrix4x4_Transform3x3(m, normal3f, n);
1369 if ((dot = DotProduct(n, v)) > 0)
1372 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1373 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1374 VectorScale(lightcolor, intensity, color4f);
1379 VectorClear(color4f);
1385 VectorClear(color4f);
1391 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1393 float *color4f = varray_color4f;
1394 float dist, dot, intensity, v[3], n[3];
1395 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1397 Matrix4x4_Transform(m, vertex3f, v);
1398 if ((dist = fabs(v[2])) < 1)
1400 Matrix4x4_Transform3x3(m, normal3f, n);
1401 if ((dot = DotProduct(n, v)) > 0)
1403 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1404 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1405 VectorScale(lightcolor, intensity, color4f);
1410 VectorClear(color4f);
1416 VectorClear(color4f);
1422 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1424 float *color4f = varray_color4f;
1425 float dot, intensity, v[3], n[3];
1426 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1428 Matrix4x4_Transform(m, vertex3f, v);
1429 Matrix4x4_Transform3x3(m, normal3f, n);
1430 if ((dot = DotProduct(n, v)) > 0)
1432 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1433 VectorScale(lightcolor, intensity, color4f);
1438 VectorClear(color4f);
1444 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1446 float *color4f = varray_color4f;
1447 float dist, intensity, v[3];
1448 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1450 Matrix4x4_Transform(m, vertex3f, v);
1451 if ((dist = DotProduct(v, v)) < 1)
1454 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1455 VectorScale(lightcolor, intensity, color4f);
1460 VectorClear(color4f);
1466 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1468 float *color4f = varray_color4f;
1469 float dist, intensity, v[3];
1470 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1472 Matrix4x4_Transform(m, vertex3f, v);
1473 if ((dist = fabs(v[2])) < 1)
1475 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1476 VectorScale(lightcolor, intensity, color4f);
1481 VectorClear(color4f);
1487 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1488 #define USETEXMATRIX
1490 #ifndef USETEXMATRIX
1491 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1492 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1493 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1497 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1498 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1499 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1506 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1510 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1511 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1519 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
1523 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1525 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1526 // the cubemap normalizes this for us
1527 out3f[0] = DotProduct(svector3f, lightdir);
1528 out3f[1] = DotProduct(tvector3f, lightdir);
1529 out3f[2] = DotProduct(normal3f, lightdir);
1533 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
1536 float lightdir[3], eyedir[3], halfdir[3];
1537 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1539 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1540 VectorNormalizeFast(lightdir);
1541 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1542 VectorNormalizeFast(eyedir);
1543 VectorAdd(lightdir, eyedir, halfdir);
1544 // the cubemap normalizes this for us
1545 out3f[0] = DotProduct(svector3f, halfdir);
1546 out3f[1] = DotProduct(tvector3f, halfdir);
1547 out3f[2] = DotProduct(normal3f, halfdir);
1551 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
1554 float color[3], color2[3], colorscale;
1557 bumptexture = r_texture_blanknormalmap;
1558 if (!lightcolorbase)
1559 lightcolorbase = vec3_origin;
1560 if (!lightcolorpants)
1561 lightcolorpants = vec3_origin;
1562 if (!lightcolorshirt)
1563 lightcolorshirt = vec3_origin;
1564 specularscale *= r_shadow_glossintensity.value;
1567 if (r_shadow_gloss.integer >= 2)
1569 glosstexture = r_texture_white;
1570 specularscale *= r_shadow_gloss2intensity.value;
1574 glosstexture = r_texture_black;
1578 if (r_shadow_gloss.integer < 1)
1581 lightcubemap = r_shadow_blankwhitecubetexture;
1582 if ((ambientscale + diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1584 // FIXME: support EF_NODEPTHTEST
1585 GL_DepthMask(false);
1587 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1589 unsigned int perm, prog;
1590 // GLSL shader path (GFFX5200, Radeon 9500)
1591 memset(&m, 0, sizeof(m));
1592 m.pointer_vertex = vertex3f;
1593 m.pointer_texcoord[0] = texcoord2f;
1594 m.pointer_texcoord3f[1] = svector3f;
1595 m.pointer_texcoord3f[2] = tvector3f;
1596 m.pointer_texcoord3f[3] = normal3f;
1597 m.tex[0] = R_GetTexture(bumptexture);
1598 m.tex[1] = R_GetTexture(basetexture);
1599 m.tex[2] = R_GetTexture(glosstexture);
1600 m.texcubemap[3] = R_GetTexture(lightcubemap);
1601 // TODO: support fog (after renderer is converted to texture fog)
1602 m.tex[4] = R_GetTexture(r_texture_white);
1603 m.texmatrix[3] = *matrix_modeltolight;
1605 GL_BlendFunc(GL_ONE, GL_ONE);
1606 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1609 // only add a feature to the permutation if that permutation exists
1610 // (otherwise it might end up not using a shader at all, which looks
1611 // worse than using less features)
1612 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1613 perm |= SHADERPERMUTATION_SPECULAR;
1614 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1615 // perm |= SHADERPERMUTATION_FOG;
1616 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1617 perm |= SHADERPERMUTATION_CUBEFILTER;
1618 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1619 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1620 prog = r_shadow_program_light[perm];
1621 qglUseProgramObjectARB(prog);CHECKGLERROR
1622 // TODO: support fog (after renderer is converted to texture fog)
1623 if (perm & SHADERPERMUTATION_FOG)
1625 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1627 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1628 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1629 if (perm & SHADERPERMUTATION_SPECULAR)
1631 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1632 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1634 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1635 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1636 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1638 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1640 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1642 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1643 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1646 GL_LockArrays(firstvertex, numvertices);
1647 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1649 c_rt_lighttris += numtriangles;
1650 // TODO: add direct pants/shirt rendering
1651 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1653 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1654 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1655 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1657 c_rt_lighttris += numtriangles;
1659 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1661 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1662 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1663 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1665 c_rt_lighttris += numtriangles;
1667 GL_LockArrays(0, 0);
1668 qglUseProgramObjectARB(0);
1669 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1670 qglBegin(GL_TRIANGLES);
1674 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1676 // TODO: add direct pants/shirt rendering
1677 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1678 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale);
1679 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1680 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale);
1682 bumptexture = r_texture_blanknormalmap;
1684 glosstexture = r_texture_white;
1688 colorscale = ambientscale;
1689 // colorscale accounts for how much we multiply the brightness
1692 // mult is how many times the final pass of the lighting will be
1693 // performed to get more brightness than otherwise possible.
1695 // Limit mult to 64 for sanity sake.
1696 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1698 // 3 3D combine path (Geforce3, Radeon 8500)
1699 memset(&m, 0, sizeof(m));
1700 m.pointer_vertex = vertex3f;
1701 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1703 m.pointer_texcoord3f[0] = vertex3f;
1704 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1706 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1707 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1709 m.tex[1] = R_GetTexture(basetexture);
1710 m.pointer_texcoord[1] = texcoord2f;
1711 m.texcubemap[2] = R_GetTexture(lightcubemap);
1713 m.pointer_texcoord3f[2] = vertex3f;
1714 m.texmatrix[2] = *matrix_modeltolight;
1716 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1717 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1719 GL_BlendFunc(GL_ONE, GL_ONE);
1721 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1723 // 2 3D combine path (Geforce3, original Radeon)
1724 memset(&m, 0, sizeof(m));
1725 m.pointer_vertex = vertex3f;
1726 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1728 m.pointer_texcoord3f[0] = vertex3f;
1729 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1731 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1732 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1734 m.tex[1] = R_GetTexture(basetexture);
1735 m.pointer_texcoord[1] = texcoord2f;
1736 GL_BlendFunc(GL_ONE, GL_ONE);
1738 else if (r_textureunits.integer >= 4 && lightcubemap)
1740 // 4 2D combine path (Geforce3, Radeon 8500)
1741 memset(&m, 0, sizeof(m));
1742 m.pointer_vertex = vertex3f;
1743 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1745 m.pointer_texcoord3f[0] = vertex3f;
1746 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1748 m.pointer_texcoord[0] = varray_texcoord2f[0];
1749 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1751 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1753 m.pointer_texcoord3f[1] = vertex3f;
1754 m.texmatrix[1] = *matrix_modeltoattenuationz;
1756 m.pointer_texcoord[1] = varray_texcoord2f[1];
1757 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1759 m.tex[2] = R_GetTexture(basetexture);
1760 m.pointer_texcoord[2] = texcoord2f;
1763 m.texcubemap[3] = R_GetTexture(lightcubemap);
1765 m.pointer_texcoord3f[3] = vertex3f;
1766 m.texmatrix[3] = *matrix_modeltolight;
1768 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1769 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1772 GL_BlendFunc(GL_ONE, GL_ONE);
1774 else if (r_textureunits.integer >= 3 && !lightcubemap)
1776 // 3 2D combine path (Geforce3, original Radeon)
1777 memset(&m, 0, sizeof(m));
1778 m.pointer_vertex = vertex3f;
1779 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1781 m.pointer_texcoord3f[0] = vertex3f;
1782 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1784 m.pointer_texcoord[0] = varray_texcoord2f[0];
1785 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1787 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1789 m.pointer_texcoord3f[1] = vertex3f;
1790 m.texmatrix[1] = *matrix_modeltoattenuationz;
1792 m.pointer_texcoord[1] = varray_texcoord2f[1];
1793 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1795 m.tex[2] = R_GetTexture(basetexture);
1796 m.pointer_texcoord[2] = texcoord2f;
1797 GL_BlendFunc(GL_ONE, GL_ONE);
1801 // 2/2/2 2D combine path (any dot3 card)
1802 memset(&m, 0, sizeof(m));
1803 m.pointer_vertex = vertex3f;
1804 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1806 m.pointer_texcoord3f[0] = vertex3f;
1807 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1809 m.pointer_texcoord[0] = varray_texcoord2f[0];
1810 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1812 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1814 m.pointer_texcoord3f[1] = vertex3f;
1815 m.texmatrix[1] = *matrix_modeltoattenuationz;
1817 m.pointer_texcoord[1] = varray_texcoord2f[1];
1818 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1821 GL_ColorMask(0,0,0,1);
1822 GL_BlendFunc(GL_ONE, GL_ZERO);
1823 GL_LockArrays(firstvertex, numvertices);
1824 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1825 GL_LockArrays(0, 0);
1827 c_rt_lighttris += numtriangles;
1829 memset(&m, 0, sizeof(m));
1830 m.pointer_vertex = vertex3f;
1831 m.tex[0] = R_GetTexture(basetexture);
1832 m.pointer_texcoord[0] = texcoord2f;
1835 m.texcubemap[1] = R_GetTexture(lightcubemap);
1837 m.pointer_texcoord3f[1] = vertex3f;
1838 m.texmatrix[1] = *matrix_modeltolight;
1840 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1841 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1844 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1846 // this final code is shared
1848 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1849 VectorScale(lightcolorbase, colorscale, color2);
1850 GL_LockArrays(firstvertex, numvertices);
1851 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1853 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1854 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1856 c_rt_lighttris += numtriangles;
1858 GL_LockArrays(0, 0);
1863 colorscale = diffusescale;
1864 // colorscale accounts for how much we multiply the brightness
1867 // mult is how many times the final pass of the lighting will be
1868 // performed to get more brightness than otherwise possible.
1870 // Limit mult to 64 for sanity sake.
1871 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1873 // 3/2 3D combine path (Geforce3, Radeon 8500)
1874 memset(&m, 0, sizeof(m));
1875 m.pointer_vertex = vertex3f;
1876 m.tex[0] = R_GetTexture(bumptexture);
1877 m.texcombinergb[0] = GL_REPLACE;
1878 m.pointer_texcoord[0] = texcoord2f;
1879 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1880 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1881 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1882 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1883 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1885 m.pointer_texcoord3f[2] = vertex3f;
1886 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1888 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1889 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1892 GL_ColorMask(0,0,0,1);
1893 GL_BlendFunc(GL_ONE, GL_ZERO);
1894 GL_LockArrays(firstvertex, numvertices);
1895 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1896 GL_LockArrays(0, 0);
1898 c_rt_lighttris += numtriangles;
1900 memset(&m, 0, sizeof(m));
1901 m.pointer_vertex = vertex3f;
1902 m.tex[0] = R_GetTexture(basetexture);
1903 m.pointer_texcoord[0] = texcoord2f;
1906 m.texcubemap[1] = R_GetTexture(lightcubemap);
1908 m.pointer_texcoord3f[1] = vertex3f;
1909 m.texmatrix[1] = *matrix_modeltolight;
1911 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1912 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1915 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1917 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1919 // 1/2/2 3D combine path (original Radeon)
1920 memset(&m, 0, sizeof(m));
1921 m.pointer_vertex = vertex3f;
1922 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1924 m.pointer_texcoord3f[0] = vertex3f;
1925 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1927 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1928 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1931 GL_ColorMask(0,0,0,1);
1932 GL_BlendFunc(GL_ONE, GL_ZERO);
1933 GL_LockArrays(firstvertex, numvertices);
1934 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1935 GL_LockArrays(0, 0);
1937 c_rt_lighttris += numtriangles;
1939 memset(&m, 0, sizeof(m));
1940 m.pointer_vertex = vertex3f;
1941 m.tex[0] = R_GetTexture(bumptexture);
1942 m.texcombinergb[0] = GL_REPLACE;
1943 m.pointer_texcoord[0] = texcoord2f;
1944 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1945 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1946 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1947 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1949 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1950 GL_LockArrays(firstvertex, numvertices);
1951 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1952 GL_LockArrays(0, 0);
1954 c_rt_lighttris += numtriangles;
1956 memset(&m, 0, sizeof(m));
1957 m.pointer_vertex = vertex3f;
1958 m.tex[0] = R_GetTexture(basetexture);
1959 m.pointer_texcoord[0] = texcoord2f;
1962 m.texcubemap[1] = R_GetTexture(lightcubemap);
1964 m.pointer_texcoord3f[1] = vertex3f;
1965 m.texmatrix[1] = *matrix_modeltolight;
1967 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1968 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1971 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1973 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1975 // 2/2 3D combine path (original Radeon)
1976 memset(&m, 0, sizeof(m));
1977 m.pointer_vertex = vertex3f;
1978 m.tex[0] = R_GetTexture(bumptexture);
1979 m.texcombinergb[0] = GL_REPLACE;
1980 m.pointer_texcoord[0] = texcoord2f;
1981 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1982 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1983 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1984 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
1986 GL_ColorMask(0,0,0,1);
1987 GL_BlendFunc(GL_ONE, GL_ZERO);
1988 GL_LockArrays(firstvertex, numvertices);
1989 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1990 GL_LockArrays(0, 0);
1992 c_rt_lighttris += numtriangles;
1994 memset(&m, 0, sizeof(m));
1995 m.pointer_vertex = vertex3f;
1996 m.tex[0] = R_GetTexture(basetexture);
1997 m.pointer_texcoord[0] = texcoord2f;
1998 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2000 m.pointer_texcoord3f[1] = vertex3f;
2001 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2003 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2004 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2006 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2008 else if (r_textureunits.integer >= 4)
2010 // 4/2 2D combine path (Geforce3, Radeon 8500)
2011 memset(&m, 0, sizeof(m));
2012 m.pointer_vertex = vertex3f;
2013 m.tex[0] = R_GetTexture(bumptexture);
2014 m.texcombinergb[0] = GL_REPLACE;
2015 m.pointer_texcoord[0] = texcoord2f;
2016 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2017 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2018 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2019 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2020 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2022 m.pointer_texcoord3f[2] = vertex3f;
2023 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2025 m.pointer_texcoord[2] = varray_texcoord2f[2];
2026 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2028 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2030 m.pointer_texcoord3f[3] = vertex3f;
2031 m.texmatrix[3] = *matrix_modeltoattenuationz;
2033 m.pointer_texcoord[3] = varray_texcoord2f[3];
2034 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2037 GL_ColorMask(0,0,0,1);
2038 GL_BlendFunc(GL_ONE, GL_ZERO);
2039 GL_LockArrays(firstvertex, numvertices);
2040 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2041 GL_LockArrays(0, 0);
2043 c_rt_lighttris += numtriangles;
2045 memset(&m, 0, sizeof(m));
2046 m.pointer_vertex = vertex3f;
2047 m.tex[0] = R_GetTexture(basetexture);
2048 m.pointer_texcoord[0] = texcoord2f;
2051 m.texcubemap[1] = R_GetTexture(lightcubemap);
2053 m.pointer_texcoord3f[1] = vertex3f;
2054 m.texmatrix[1] = *matrix_modeltolight;
2056 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2057 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2060 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2064 // 2/2/2 2D combine path (any dot3 card)
2065 memset(&m, 0, sizeof(m));
2066 m.pointer_vertex = vertex3f;
2067 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2069 m.pointer_texcoord3f[0] = vertex3f;
2070 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2072 m.pointer_texcoord[0] = varray_texcoord2f[0];
2073 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2075 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2077 m.pointer_texcoord3f[1] = vertex3f;
2078 m.texmatrix[1] = *matrix_modeltoattenuationz;
2080 m.pointer_texcoord[1] = varray_texcoord2f[1];
2081 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2084 GL_ColorMask(0,0,0,1);
2085 GL_BlendFunc(GL_ONE, GL_ZERO);
2086 GL_LockArrays(firstvertex, numvertices);
2087 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2088 GL_LockArrays(0, 0);
2090 c_rt_lighttris += numtriangles;
2092 memset(&m, 0, sizeof(m));
2093 m.pointer_vertex = vertex3f;
2094 m.tex[0] = R_GetTexture(bumptexture);
2095 m.texcombinergb[0] = GL_REPLACE;
2096 m.pointer_texcoord[0] = texcoord2f;
2097 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2098 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2099 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2100 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2102 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2103 GL_LockArrays(firstvertex, numvertices);
2104 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2105 GL_LockArrays(0, 0);
2107 c_rt_lighttris += numtriangles;
2109 memset(&m, 0, sizeof(m));
2110 m.pointer_vertex = vertex3f;
2111 m.tex[0] = R_GetTexture(basetexture);
2112 m.pointer_texcoord[0] = texcoord2f;
2115 m.texcubemap[1] = R_GetTexture(lightcubemap);
2117 m.pointer_texcoord3f[1] = vertex3f;
2118 m.texmatrix[1] = *matrix_modeltolight;
2120 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2121 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2124 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2126 // this final code is shared
2128 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2129 VectorScale(lightcolorbase, colorscale, color2);
2130 GL_LockArrays(firstvertex, numvertices);
2131 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2133 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2134 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2136 c_rt_lighttris += numtriangles;
2138 GL_LockArrays(0, 0);
2140 if (specularscale && glosstexture != r_texture_black)
2142 // FIXME: detect blendsquare!
2143 //if (gl_support_blendsquare)
2145 colorscale = specularscale;
2147 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2149 // 2/0/0/1/2 3D combine blendsquare path
2150 memset(&m, 0, sizeof(m));
2151 m.pointer_vertex = vertex3f;
2152 m.tex[0] = R_GetTexture(bumptexture);
2153 m.pointer_texcoord[0] = texcoord2f;
2154 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2155 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2156 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2157 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);
2159 GL_ColorMask(0,0,0,1);
2160 // this squares the result
2161 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2162 GL_LockArrays(firstvertex, numvertices);
2163 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2164 GL_LockArrays(0, 0);
2166 c_rt_lighttris += numtriangles;
2168 memset(&m, 0, sizeof(m));
2169 m.pointer_vertex = vertex3f;
2171 GL_LockArrays(firstvertex, numvertices);
2172 // square alpha in framebuffer a few times to make it shiny
2173 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2174 // these comments are a test run through this math for intensity 0.5
2175 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2176 // 0.25 * 0.25 = 0.0625 (this is another pass)
2177 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2178 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2180 c_rt_lighttris += numtriangles;
2181 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2183 c_rt_lighttris += numtriangles;
2184 GL_LockArrays(0, 0);
2186 memset(&m, 0, sizeof(m));
2187 m.pointer_vertex = vertex3f;
2188 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2190 m.pointer_texcoord3f[0] = vertex3f;
2191 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2193 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2194 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2197 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2198 GL_LockArrays(firstvertex, numvertices);
2199 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2200 GL_LockArrays(0, 0);
2202 c_rt_lighttris += numtriangles;
2204 memset(&m, 0, sizeof(m));
2205 m.pointer_vertex = vertex3f;
2206 m.tex[0] = R_GetTexture(glosstexture);
2207 m.pointer_texcoord[0] = texcoord2f;
2210 m.texcubemap[1] = R_GetTexture(lightcubemap);
2212 m.pointer_texcoord3f[1] = vertex3f;
2213 m.texmatrix[1] = *matrix_modeltolight;
2215 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2216 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2219 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2221 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2223 // 2/0/0/2 3D combine blendsquare path
2224 memset(&m, 0, sizeof(m));
2225 m.pointer_vertex = vertex3f;
2226 m.tex[0] = R_GetTexture(bumptexture);
2227 m.pointer_texcoord[0] = texcoord2f;
2228 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2229 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2230 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2231 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2233 GL_ColorMask(0,0,0,1);
2234 // this squares the result
2235 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2236 GL_LockArrays(firstvertex, numvertices);
2237 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2238 GL_LockArrays(0, 0);
2240 c_rt_lighttris += numtriangles;
2242 memset(&m, 0, sizeof(m));
2243 m.pointer_vertex = vertex3f;
2245 GL_LockArrays(firstvertex, numvertices);
2246 // square alpha in framebuffer a few times to make it shiny
2247 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2248 // these comments are a test run through this math for intensity 0.5
2249 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2250 // 0.25 * 0.25 = 0.0625 (this is another pass)
2251 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2252 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2254 c_rt_lighttris += numtriangles;
2255 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2257 c_rt_lighttris += numtriangles;
2258 GL_LockArrays(0, 0);
2260 memset(&m, 0, sizeof(m));
2261 m.pointer_vertex = vertex3f;
2262 m.tex[0] = R_GetTexture(glosstexture);
2263 m.pointer_texcoord[0] = texcoord2f;
2264 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2266 m.pointer_texcoord3f[1] = vertex3f;
2267 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2269 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2270 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2272 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2276 // 2/0/0/2/2 2D combine blendsquare path
2277 memset(&m, 0, sizeof(m));
2278 m.pointer_vertex = vertex3f;
2279 m.tex[0] = R_GetTexture(bumptexture);
2280 m.pointer_texcoord[0] = texcoord2f;
2281 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2282 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2283 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2284 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);
2286 GL_ColorMask(0,0,0,1);
2287 // this squares the result
2288 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2289 GL_LockArrays(firstvertex, numvertices);
2290 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2291 GL_LockArrays(0, 0);
2293 c_rt_lighttris += numtriangles;
2295 memset(&m, 0, sizeof(m));
2296 m.pointer_vertex = vertex3f;
2298 GL_LockArrays(firstvertex, numvertices);
2299 // square alpha in framebuffer a few times to make it shiny
2300 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2301 // these comments are a test run through this math for intensity 0.5
2302 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2303 // 0.25 * 0.25 = 0.0625 (this is another pass)
2304 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2305 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2307 c_rt_lighttris += numtriangles;
2308 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2310 c_rt_lighttris += numtriangles;
2311 GL_LockArrays(0, 0);
2313 memset(&m, 0, sizeof(m));
2314 m.pointer_vertex = vertex3f;
2315 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2317 m.pointer_texcoord3f[0] = vertex3f;
2318 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2320 m.pointer_texcoord[0] = varray_texcoord2f[0];
2321 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2323 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2325 m.pointer_texcoord3f[1] = vertex3f;
2326 m.texmatrix[1] = *matrix_modeltoattenuationz;
2328 m.pointer_texcoord[1] = varray_texcoord2f[1];
2329 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2332 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2333 GL_LockArrays(firstvertex, numvertices);
2334 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2335 GL_LockArrays(0, 0);
2337 c_rt_lighttris += numtriangles;
2339 memset(&m, 0, sizeof(m));
2340 m.pointer_vertex = vertex3f;
2341 m.tex[0] = R_GetTexture(glosstexture);
2342 m.pointer_texcoord[0] = texcoord2f;
2345 m.texcubemap[1] = R_GetTexture(lightcubemap);
2347 m.pointer_texcoord3f[1] = vertex3f;
2348 m.texmatrix[1] = *matrix_modeltolight;
2350 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2351 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2354 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2357 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2358 VectorScale(lightcolorbase, colorscale, color2);
2359 GL_LockArrays(firstvertex, numvertices);
2360 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2362 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2363 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2365 c_rt_lighttris += numtriangles;
2367 GL_LockArrays(0, 0);
2373 // TODO: add direct pants/shirt rendering
2374 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2375 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale);
2376 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2377 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale);
2380 GL_BlendFunc(GL_ONE, GL_ONE);
2381 VectorScale(lightcolorbase, ambientscale, color2);
2382 memset(&m, 0, sizeof(m));
2383 m.pointer_vertex = vertex3f;
2384 m.tex[0] = R_GetTexture(basetexture);
2385 m.pointer_texcoord[0] = texcoord2f;
2386 if (r_textureunits.integer >= 2)
2389 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2391 m.pointer_texcoord3f[1] = vertex3f;
2392 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2394 m.pointer_texcoord[1] = varray_texcoord2f[1];
2395 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2397 if (r_textureunits.integer >= 3)
2399 // Geforce3/Radeon class but not using dot3
2400 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2402 m.pointer_texcoord3f[2] = vertex3f;
2403 m.texmatrix[2] = *matrix_modeltoattenuationz;
2405 m.pointer_texcoord[2] = varray_texcoord2f[2];
2406 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2410 if (r_textureunits.integer >= 3)
2411 m.pointer_color = NULL;
2413 m.pointer_color = varray_color4f;
2415 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2417 color[0] = bound(0, color2[0], 1);
2418 color[1] = bound(0, color2[1], 1);
2419 color[2] = bound(0, color2[2], 1);
2420 if (r_textureunits.integer >= 3)
2421 GL_Color(color[0], color[1], color[2], 1);
2422 else if (r_textureunits.integer >= 2)
2423 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2425 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2426 GL_LockArrays(firstvertex, numvertices);
2427 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2428 GL_LockArrays(0, 0);
2430 c_rt_lighttris += numtriangles;
2435 GL_BlendFunc(GL_ONE, GL_ONE);
2436 VectorScale(lightcolorbase, diffusescale, color2);
2437 memset(&m, 0, sizeof(m));
2438 m.pointer_vertex = vertex3f;
2439 m.pointer_color = varray_color4f;
2440 m.tex[0] = R_GetTexture(basetexture);
2441 m.pointer_texcoord[0] = texcoord2f;
2442 if (r_textureunits.integer >= 2)
2445 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2447 m.pointer_texcoord3f[1] = vertex3f;
2448 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2450 m.pointer_texcoord[1] = varray_texcoord2f[1];
2451 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2453 if (r_textureunits.integer >= 3)
2455 // Geforce3/Radeon class but not using dot3
2456 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2458 m.pointer_texcoord3f[2] = vertex3f;
2459 m.texmatrix[2] = *matrix_modeltoattenuationz;
2461 m.pointer_texcoord[2] = varray_texcoord2f[2];
2462 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2467 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2469 color[0] = bound(0, color2[0], 1);
2470 color[1] = bound(0, color2[1], 1);
2471 color[2] = bound(0, color2[2], 1);
2472 if (r_textureunits.integer >= 3)
2473 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2474 else if (r_textureunits.integer >= 2)
2475 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2477 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2478 GL_LockArrays(firstvertex, numvertices);
2479 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2480 GL_LockArrays(0, 0);
2482 c_rt_lighttris += numtriangles;
2488 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2492 R_RTLight_Uncompile(rtlight);
2493 memset(rtlight, 0, sizeof(*rtlight));
2495 VectorCopy(light->origin, rtlight->shadoworigin);
2496 VectorCopy(light->color, rtlight->color);
2497 rtlight->radius = light->radius;
2498 //rtlight->cullradius = rtlight->radius;
2499 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2500 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2501 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2502 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2503 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2504 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2505 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2506 rtlight->cubemapname[0] = 0;
2507 if (light->cubemapname[0])
2508 strcpy(rtlight->cubemapname, light->cubemapname);
2509 else if (light->cubemapnum > 0)
2510 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2511 rtlight->shadow = light->shadow;
2512 rtlight->corona = light->corona;
2513 rtlight->style = light->style;
2514 rtlight->isstatic = isstatic;
2515 rtlight->coronasizescale = light->coronasizescale;
2516 rtlight->ambientscale = light->ambientscale;
2517 rtlight->diffusescale = light->diffusescale;
2518 rtlight->specularscale = light->specularscale;
2519 rtlight->flags = light->flags;
2520 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2521 // ConcatScale won't work here because this needs to scale rotate and
2522 // translate, not just rotate
2523 scale = 1.0f / rtlight->radius;
2524 for (k = 0;k < 3;k++)
2525 for (j = 0;j < 4;j++)
2526 rtlight->matrix_worldtolight.m[k][j] *= scale;
2527 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2528 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2530 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2531 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2532 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2533 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2536 // compiles rtlight geometry
2537 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2538 void R_RTLight_Compile(rtlight_t *rtlight)
2540 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2541 entity_render_t *ent = r_refdef.worldentity;
2542 model_t *model = r_refdef.worldmodel;
2544 // compile the light
2545 rtlight->compiled = true;
2546 rtlight->static_numclusters = 0;
2547 rtlight->static_numclusterpvsbytes = 0;
2548 rtlight->static_clusterlist = NULL;
2549 rtlight->static_clusterpvs = NULL;
2550 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2551 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2552 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2553 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2554 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2555 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2557 if (model && model->GetLightInfo)
2559 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2560 r_shadow_compilingrtlight = rtlight;
2561 R_Shadow_EnlargeClusterSurfaceBuffer(model->brush.num_pvsclusters, model->nummodelsurfaces);
2562 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);
2563 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2564 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2567 rtlight->static_numclusters = numclusters;
2568 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2569 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2570 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2572 if (model->DrawShadowVolume && rtlight->shadow)
2574 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2575 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2576 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2578 if (model->DrawLight)
2580 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2581 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);
2582 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2584 // switch back to rendering when DrawShadowVolume or DrawLight is called
2585 r_shadow_compilingrtlight = NULL;
2589 // use smallest available cullradius - box radius or light radius
2590 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2591 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2595 if (rtlight->static_meshchain_shadow)
2598 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2601 shadowtris += mesh->numtriangles;
2607 if (rtlight->static_meshchain_light)
2610 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2613 lighttris += mesh->numtriangles;
2617 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);
2620 void R_RTLight_Uncompile(rtlight_t *rtlight)
2622 if (rtlight->compiled)
2624 if (rtlight->static_meshchain_shadow)
2625 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2626 rtlight->static_meshchain_shadow = NULL;
2627 if (rtlight->static_meshchain_light)
2628 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2629 rtlight->static_meshchain_light = NULL;
2630 if (rtlight->static_clusterlist)
2631 Mem_Free(rtlight->static_clusterlist);
2632 rtlight->static_clusterlist = NULL;
2633 if (rtlight->static_clusterpvs)
2634 Mem_Free(rtlight->static_clusterpvs);
2635 rtlight->static_clusterpvs = NULL;
2636 rtlight->static_numclusters = 0;
2637 rtlight->static_numclusterpvsbytes = 0;
2638 rtlight->compiled = false;
2642 void R_Shadow_UncompileWorldLights(void)
2645 for (light = r_shadow_worldlightchain;light;light = light->next)
2646 R_RTLight_Uncompile(&light->rtlight);
2649 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2651 int i, shadow, usestencil;
2652 entity_render_t *ent;
2654 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2655 rtexture_t *cubemaptexture;
2656 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2657 int numclusters, numsurfaces;
2658 int *clusterlist, *surfacelist;
2660 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2664 // skip lights that don't light (corona only lights)
2665 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2668 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2669 VectorScale(rtlight->color, f, lightcolor);
2670 if (VectorLength2(lightcolor) < 0.01)
2673 if (rtlight->selected)
2675 f = 2 + sin(realtime * M_PI * 4.0);
2676 VectorScale(lightcolor, f, lightcolor);
2680 // loading is done before visibility checks because loading should happen
2681 // all at once at the start of a level, not when it stalls gameplay.
2682 // (especially important to benchmarks)
2683 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2684 R_RTLight_Compile(rtlight);
2685 if (rtlight->cubemapname[0])
2686 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2688 cubemaptexture = NULL;
2690 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2691 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2692 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2693 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2694 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2695 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2696 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2703 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2705 // compiled light, world available and can receive realtime lighting
2706 // retrieve cluster information
2707 numclusters = rtlight->static_numclusters;
2708 clusterlist = rtlight->static_clusterlist;
2709 clusterpvs = rtlight->static_clusterpvs;
2710 VectorCopy(rtlight->cullmins, cullmins);
2711 VectorCopy(rtlight->cullmaxs, cullmaxs);
2713 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2715 // dynamic light, world available and can receive realtime lighting
2716 // if the light box is offscreen, skip it right away
2717 if (R_CullBox(cullmins, cullmaxs))
2719 // calculate lit surfaces and clusters
2720 R_Shadow_EnlargeClusterSurfaceBuffer(r_refdef.worldmodel->brush.num_pvsclusters, r_refdef.worldmodel->nummodelsurfaces);
2721 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);
2722 clusterlist = r_shadow_buffer_clusterlist;
2723 clusterpvs = r_shadow_buffer_clusterpvs;
2724 surfacelist = r_shadow_buffer_surfacelist;
2726 // if the reduced cluster bounds are offscreen, skip it
2727 if (R_CullBox(cullmins, cullmaxs))
2729 // check if light is illuminating any visible clusters
2732 for (i = 0;i < numclusters;i++)
2733 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2735 if (i == numclusters)
2738 // set up a scissor rectangle for this light
2739 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2742 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2745 if (shadow && (gl_stencil || visiblevolumes))
2747 if (!visiblevolumes)
2749 R_Shadow_Stage_ShadowVolumes();
2752 ent = r_refdef.worldentity;
2753 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2755 memset(&m, 0, sizeof(m));
2756 R_Mesh_Matrix(&ent->matrix);
2757 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2759 m.pointer_vertex = mesh->vertex3f;
2761 GL_LockArrays(0, mesh->numverts);
2762 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2764 // increment stencil if backface is behind depthbuffer
2765 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2766 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2767 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2768 c_rtcached_shadowmeshes++;
2769 c_rtcached_shadowtris += mesh->numtriangles;
2770 // decrement stencil if frontface is behind depthbuffer
2771 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2772 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2774 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2775 c_rtcached_shadowmeshes++;
2776 c_rtcached_shadowtris += mesh->numtriangles;
2777 GL_LockArrays(0, 0);
2780 else if (numsurfaces)
2782 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2783 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2785 if (r_drawentities.integer)
2787 for (i = 0;i < r_refdef.numentities;i++)
2789 ent = r_refdef.entities[i];
2791 if (r_shadow_cull.integer)
2793 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2795 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2798 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2800 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2801 // light emitting entities should not cast their own shadow
2802 if (VectorLength2(relativelightorigin) < 0.1)
2804 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2805 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2806 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2807 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2808 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2809 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2810 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2815 if (!visiblevolumes)
2817 R_Shadow_Stage_Light(usestencil);
2819 ent = r_refdef.worldentity;
2820 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2822 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2823 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2824 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2825 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2826 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2827 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2828 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2829 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2830 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2832 R_Mesh_Matrix(&ent->matrix);
2833 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2834 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, NULL, NULL, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
2837 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2839 if (r_drawentities.integer)
2841 for (i = 0;i < r_refdef.numentities;i++)
2843 ent = r_refdef.entities[i];
2844 // can't draw transparent entity lighting here because
2845 // transparent meshes are deferred for later
2846 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)
2848 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2849 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2850 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2851 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2852 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2853 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2854 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2855 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2856 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);
2863 void R_ShadowVolumeLighting(int visiblevolumes)
2869 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2870 R_Shadow_EditLights_Reload_f();
2874 memset(&m, 0, sizeof(m));
2877 GL_BlendFunc(GL_ONE, GL_ONE);
2878 GL_DepthMask(false);
2879 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2880 qglDisable(GL_CULL_FACE);
2881 GL_Color(0.0, 0.0125, 0.1, 1);
2884 R_Shadow_Stage_Begin();
2885 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2886 if (r_shadow_debuglight.integer >= 0)
2888 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2889 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2890 R_DrawRTLight(&light->rtlight, visiblevolumes);
2893 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2894 if (light->flags & flag)
2895 R_DrawRTLight(&light->rtlight, visiblevolumes);
2897 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2898 R_DrawRTLight(&light->rtlight, visiblevolumes);
2902 qglEnable(GL_CULL_FACE);
2903 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2906 R_Shadow_Stage_End();
2909 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2910 typedef struct suffixinfo_s
2913 qboolean flipx, flipy, flipdiagonal;
2916 static suffixinfo_t suffix[3][6] =
2919 {"px", false, false, false},
2920 {"nx", false, false, false},
2921 {"py", false, false, false},
2922 {"ny", false, false, false},
2923 {"pz", false, false, false},
2924 {"nz", false, false, false}
2927 {"posx", false, false, false},
2928 {"negx", false, false, false},
2929 {"posy", false, false, false},
2930 {"negy", false, false, false},
2931 {"posz", false, false, false},
2932 {"negz", false, false, false}
2935 {"rt", true, false, true},
2936 {"lf", false, true, true},
2937 {"ft", true, true, false},
2938 {"bk", false, false, false},
2939 {"up", true, false, true},
2940 {"dn", true, false, true}
2944 static int componentorder[4] = {0, 1, 2, 3};
2946 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2948 int i, j, cubemapsize;
2949 qbyte *cubemappixels, *image_rgba;
2950 rtexture_t *cubemaptexture;
2952 // must start 0 so the first loadimagepixels has no requested width/height
2954 cubemappixels = NULL;
2955 cubemaptexture = NULL;
2956 // keep trying different suffix groups (posx, px, rt) until one loads
2957 for (j = 0;j < 3 && !cubemappixels;j++)
2959 // load the 6 images in the suffix group
2960 for (i = 0;i < 6;i++)
2962 // generate an image name based on the base and and suffix
2963 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2965 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2967 // an image loaded, make sure width and height are equal
2968 if (image_width == image_height)
2970 // if this is the first image to load successfully, allocate the cubemap memory
2971 if (!cubemappixels && image_width >= 1)
2973 cubemapsize = image_width;
2974 // note this clears to black, so unavailable sides are black
2975 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2977 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2979 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_rgba, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2982 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2984 Mem_Free(image_rgba);
2988 // if a cubemap loaded, upload it
2991 if (!r_shadow_filters_texturepool)
2992 r_shadow_filters_texturepool = R_AllocTexturePool();
2993 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2994 Mem_Free(cubemappixels);
2998 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2999 for (j = 0;j < 3;j++)
3000 for (i = 0;i < 6;i++)
3001 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3002 Con_Print(" and was unable to find any of them.\n");
3004 return cubemaptexture;
3007 rtexture_t *R_Shadow_Cubemap(const char *basename)
3010 for (i = 0;i < numcubemaps;i++)
3011 if (!strcasecmp(cubemaps[i].basename, basename))
3012 return cubemaps[i].texture;
3013 if (i >= MAX_CUBEMAPS)
3016 strcpy(cubemaps[i].basename, basename);
3017 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3018 return cubemaps[i].texture;
3021 void R_Shadow_FreeCubemaps(void)
3024 R_FreeTexturePool(&r_shadow_filters_texturepool);
3027 dlight_t *R_Shadow_NewWorldLight(void)
3030 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3031 light->next = r_shadow_worldlightchain;
3032 r_shadow_worldlightchain = light;
3036 void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
3038 VectorCopy(origin, light->origin);
3039 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3040 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3041 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3042 light->color[0] = max(color[0], 0);
3043 light->color[1] = max(color[1], 0);
3044 light->color[2] = max(color[2], 0);
3045 light->radius = max(radius, 0);
3046 light->style = style;
3047 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3049 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3052 light->shadow = shadowenable;
3053 light->corona = corona;
3056 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3057 light->coronasizescale = coronasizescale;
3058 light->ambientscale = ambientscale;
3059 light->diffusescale = diffusescale;
3060 light->specularscale = specularscale;
3061 light->flags = flags;
3062 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3064 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3067 void R_Shadow_FreeWorldLight(dlight_t *light)
3069 dlight_t **lightpointer;
3070 R_RTLight_Uncompile(&light->rtlight);
3071 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3072 if (*lightpointer != light)
3073 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3074 *lightpointer = light->next;
3078 void R_Shadow_ClearWorldLights(void)
3080 while (r_shadow_worldlightchain)
3081 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3082 r_shadow_selectedlight = NULL;
3083 R_Shadow_FreeCubemaps();
3086 void R_Shadow_SelectLight(dlight_t *light)
3088 if (r_shadow_selectedlight)
3089 r_shadow_selectedlight->selected = false;
3090 r_shadow_selectedlight = light;
3091 if (r_shadow_selectedlight)
3092 r_shadow_selectedlight->selected = true;
3095 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3097 float scale = r_editlights_cursorgrid.value * 0.5f;
3098 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
3101 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3104 const dlight_t *light;
3107 if (light->selected)
3108 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3111 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
3114 void R_Shadow_DrawLightSprites(void)
3120 for (i = 0;i < 5;i++)
3122 lighttextures[i] = NULL;
3123 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3124 lighttextures[i] = pic->tex;
3127 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3128 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3129 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3132 void R_Shadow_SelectLightInView(void)
3134 float bestrating, rating, temp[3];
3135 dlight_t *best, *light;
3138 for (light = r_shadow_worldlightchain;light;light = light->next)
3140 VectorSubtract(light->origin, r_vieworigin, temp);
3141 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3144 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3145 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3147 bestrating = rating;
3152 R_Shadow_SelectLight(best);
3155 void R_Shadow_LoadWorldLights(void)
3157 int n, a, style, shadow, flags;
3158 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3159 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3160 if (r_refdef.worldmodel == NULL)
3162 Con_Print("No map loaded.\n");
3165 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3166 strlcat (name, ".rtlights", sizeof (name));
3167 lightsstring = FS_LoadFile(name, tempmempool, false);
3177 for (;COM_Parse(t, true) && strcmp(
3178 if (COM_Parse(t, true))
3180 if (com_token[0] == '!')
3183 origin[0] = atof(com_token+1);
3186 origin[0] = atof(com_token);
3191 while (*s && *s != '\n' && *s != '\r')
3197 // check for modifier flags
3204 a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
3207 flags = LIGHTFLAG_REALTIMEMODE;
3215 coronasizescale = 0.25f;
3217 VectorClear(angles);
3220 if (a < 9 || !strcmp(cubemapname, "\"\""))
3222 // remove quotes on cubemapname
3223 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3225 cubemapname[strlen(cubemapname)-1] = 0;
3226 strcpy(cubemapname, cubemapname + 1);
3230 Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
3233 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3234 radius *= r_editlights_rtlightssizescale.value;
3235 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3243 Con_Printf("invalid rtlights file \"%s\"\n", name);
3244 Mem_Free(lightsstring);
3248 void R_Shadow_SaveWorldLights(void)
3251 int bufchars, bufmaxchars;
3253 char name[MAX_QPATH];
3255 if (!r_shadow_worldlightchain)
3257 if (r_refdef.worldmodel == NULL)
3259 Con_Print("No map loaded.\n");
3262 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3263 strlcat (name, ".rtlights", sizeof (name));
3264 bufchars = bufmaxchars = 0;
3266 for (light = r_shadow_worldlightchain;light;light = light->next)
3268 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3269 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3270 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3271 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3273 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
3274 if (bufchars + (int) strlen(line) > bufmaxchars)
3276 bufmaxchars = bufchars + strlen(line) + 2048;
3278 buf = Mem_Alloc(tempmempool, bufmaxchars);
3282 memcpy(buf, oldbuf, bufchars);
3288 memcpy(buf + bufchars, line, strlen(line));
3289 bufchars += strlen(line);
3293 FS_WriteFile(name, buf, bufchars);
3298 void R_Shadow_LoadLightsFile(void)
3301 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3302 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3303 if (r_refdef.worldmodel == NULL)
3305 Con_Print("No map loaded.\n");
3308 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3309 strlcat (name, ".lights", sizeof (name));
3310 lightsstring = FS_LoadFile(name, tempmempool, false);
3318 while (*s && *s != '\n' && *s != '\r')
3324 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
3328 Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
3331 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3332 radius = bound(15, radius, 4096);
3333 VectorScale(color, (2.0f / (8388608.0f)), color);
3334 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3342 Con_Printf("invalid lights file \"%s\"\n", name);
3343 Mem_Free(lightsstring);
3347 // tyrlite/hmap2 light types in the delay field
3348 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3350 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3352 int entnum, style, islight, skin, pflags, effects, type, n;
3355 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3356 char key[256], value[1024];
3358 if (r_refdef.worldmodel == NULL)
3360 Con_Print("No map loaded.\n");
3363 // try to load a .ent file first
3364 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3365 strlcat (key, ".ent", sizeof (key));
3366 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3367 // and if that is not found, fall back to the bsp file entity string
3369 data = r_refdef.worldmodel->brush.entities;
3372 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3374 type = LIGHTTYPE_MINUSX;
3375 origin[0] = origin[1] = origin[2] = 0;
3376 originhack[0] = originhack[1] = originhack[2] = 0;
3377 angles[0] = angles[1] = angles[2] = 0;
3378 color[0] = color[1] = color[2] = 1;
3379 light[0] = light[1] = light[2] = 1;light[3] = 300;
3380 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3390 if (!COM_ParseToken(&data, false))
3392 if (com_token[0] == '}')
3393 break; // end of entity
3394 if (com_token[0] == '_')
3395 strcpy(key, com_token + 1);
3397 strcpy(key, com_token);
3398 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3399 key[strlen(key)-1] = 0;
3400 if (!COM_ParseToken(&data, false))
3402 strcpy(value, com_token);
3404 // now that we have the key pair worked out...
3405 if (!strcmp("light", key))
3407 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3411 light[0] = vec[0] * (1.0f / 256.0f);
3412 light[1] = vec[0] * (1.0f / 256.0f);
3413 light[2] = vec[0] * (1.0f / 256.0f);
3419 light[0] = vec[0] * (1.0f / 255.0f);
3420 light[1] = vec[1] * (1.0f / 255.0f);
3421 light[2] = vec[2] * (1.0f / 255.0f);
3425 else if (!strcmp("delay", key))
3427 else if (!strcmp("origin", key))
3428 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3429 else if (!strcmp("angle", key))
3430 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3431 else if (!strcmp("angles", key))
3432 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3433 else if (!strcmp("color", key))
3434 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3435 else if (!strcmp("wait", key))
3436 fadescale = atof(value);
3437 else if (!strcmp("classname", key))
3439 if (!strncmp(value, "light", 5))
3442 if (!strcmp(value, "light_fluoro"))
3447 overridecolor[0] = 1;
3448 overridecolor[1] = 1;
3449 overridecolor[2] = 1;
3451 if (!strcmp(value, "light_fluorospark"))
3456 overridecolor[0] = 1;
3457 overridecolor[1] = 1;
3458 overridecolor[2] = 1;
3460 if (!strcmp(value, "light_globe"))
3465 overridecolor[0] = 1;
3466 overridecolor[1] = 0.8;
3467 overridecolor[2] = 0.4;
3469 if (!strcmp(value, "light_flame_large_yellow"))
3474 overridecolor[0] = 1;
3475 overridecolor[1] = 0.5;
3476 overridecolor[2] = 0.1;
3478 if (!strcmp(value, "light_flame_small_yellow"))
3483 overridecolor[0] = 1;
3484 overridecolor[1] = 0.5;
3485 overridecolor[2] = 0.1;
3487 if (!strcmp(value, "light_torch_small_white"))
3492 overridecolor[0] = 1;
3493 overridecolor[1] = 0.5;
3494 overridecolor[2] = 0.1;
3496 if (!strcmp(value, "light_torch_small_walltorch"))
3501 overridecolor[0] = 1;
3502 overridecolor[1] = 0.5;
3503 overridecolor[2] = 0.1;
3507 else if (!strcmp("style", key))
3508 style = atoi(value);
3509 else if (r_refdef.worldmodel->type == mod_brushq3)
3511 if (!strcmp("scale", key))
3512 lightscale = atof(value);
3513 if (!strcmp("fade", key))
3514 fadescale = atof(value);
3516 else if (!strcmp("skin", key))
3517 skin = (int)atof(value);
3518 else if (!strcmp("pflags", key))
3519 pflags = (int)atof(value);
3520 else if (!strcmp("effects", key))
3521 effects = (int)atof(value);
3525 if (lightscale <= 0)
3529 if (color[0] == color[1] && color[0] == color[2])
3531 color[0] *= overridecolor[0];
3532 color[1] *= overridecolor[1];
3533 color[2] *= overridecolor[2];
3535 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3536 color[0] = color[0] * light[0];
3537 color[1] = color[1] * light[1];
3538 color[2] = color[2] * light[2];
3541 case LIGHTTYPE_MINUSX:
3543 case LIGHTTYPE_RECIPX:
3545 VectorScale(color, (1.0f / 16.0f), color);
3547 case LIGHTTYPE_RECIPXX:
3549 VectorScale(color, (1.0f / 16.0f), color);
3552 case LIGHTTYPE_NONE:
3556 case LIGHTTYPE_MINUSXX:
3559 VectorAdd(origin, originhack, origin);
3561 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3564 Mem_Free(entfiledata);
3568 void R_Shadow_SetCursorLocationForView(void)
3570 vec_t dist, push, frac;
3571 vec3_t dest, endpos, normal;
3572 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3573 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3576 dist = frac * r_editlights_cursordistance.value;
3577 push = r_editlights_cursorpushback.value;
3581 VectorMA(endpos, push, r_viewforward, endpos);
3582 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3584 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3585 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3586 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3589 void R_Shadow_UpdateWorldLightSelection(void)
3591 if (r_editlights.integer)
3593 R_Shadow_SetCursorLocationForView();
3594 R_Shadow_SelectLightInView();
3595 R_Shadow_DrawLightSprites();
3598 R_Shadow_SelectLight(NULL);
3601 void R_Shadow_EditLights_Clear_f(void)
3603 R_Shadow_ClearWorldLights();
3606 void R_Shadow_EditLights_Reload_f(void)
3608 if (!r_refdef.worldmodel)
3610 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3611 R_Shadow_ClearWorldLights();
3612 R_Shadow_LoadWorldLights();
3613 if (r_shadow_worldlightchain == NULL)
3615 R_Shadow_LoadLightsFile();
3616 if (r_shadow_worldlightchain == NULL)
3617 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3621 void R_Shadow_EditLights_Save_f(void)
3623 if (!r_refdef.worldmodel)
3625 R_Shadow_SaveWorldLights();
3628 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3630 R_Shadow_ClearWorldLights();
3631 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3634 void R_Shadow_EditLights_ImportLightsFile_f(void)
3636 R_Shadow_ClearWorldLights();
3637 R_Shadow_LoadLightsFile();
3640 void R_Shadow_EditLights_Spawn_f(void)
3643 if (!r_editlights.integer)
3645 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3648 if (Cmd_Argc() != 1)
3650 Con_Print("r_editlights_spawn does not take parameters\n");
3653 color[0] = color[1] = color[2] = 1;
3654 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3657 void R_Shadow_EditLights_Edit_f(void)
3659 vec3_t origin, angles, color;
3660 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3661 int style, shadows, flags, normalmode, realtimemode;
3662 char cubemapname[1024];
3663 if (!r_editlights.integer)
3665 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3668 if (!r_shadow_selectedlight)
3670 Con_Print("No selected light.\n");
3673 VectorCopy(r_shadow_selectedlight->origin, origin);
3674 VectorCopy(r_shadow_selectedlight->angles, angles);
3675 VectorCopy(r_shadow_selectedlight->color, color);
3676 radius = r_shadow_selectedlight->radius;
3677 style = r_shadow_selectedlight->style;
3678 if (r_shadow_selectedlight->cubemapname)
3679 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3682 shadows = r_shadow_selectedlight->shadow;
3683 corona = r_shadow_selectedlight->corona;
3684 coronasizescale = r_shadow_selectedlight->coronasizescale;
3685 ambientscale = r_shadow_selectedlight->ambientscale;
3686 diffusescale = r_shadow_selectedlight->diffusescale;
3687 specularscale = r_shadow_selectedlight->specularscale;
3688 flags = r_shadow_selectedlight->flags;
3689 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3690 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3691 if (!strcmp(Cmd_Argv(1), "origin"))
3693 if (Cmd_Argc() != 5)
3695 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3698 origin[0] = atof(Cmd_Argv(2));
3699 origin[1] = atof(Cmd_Argv(3));
3700 origin[2] = atof(Cmd_Argv(4));
3702 else if (!strcmp(Cmd_Argv(1), "originx"))
3704 if (Cmd_Argc() != 3)
3706 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3709 origin[0] = atof(Cmd_Argv(2));
3711 else if (!strcmp(Cmd_Argv(1), "originy"))
3713 if (Cmd_Argc() != 3)
3715 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3718 origin[1] = atof(Cmd_Argv(2));
3720 else if (!strcmp(Cmd_Argv(1), "originz"))
3722 if (Cmd_Argc() != 3)
3724 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3727 origin[2] = atof(Cmd_Argv(2));
3729 else if (!strcmp(Cmd_Argv(1), "move"))
3731 if (Cmd_Argc() != 5)
3733 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3736 origin[0] += atof(Cmd_Argv(2));
3737 origin[1] += atof(Cmd_Argv(3));
3738 origin[2] += atof(Cmd_Argv(4));
3740 else if (!strcmp(Cmd_Argv(1), "movex"))
3742 if (Cmd_Argc() != 3)
3744 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3747 origin[0] += atof(Cmd_Argv(2));
3749 else if (!strcmp(Cmd_Argv(1), "movey"))
3751 if (Cmd_Argc() != 3)
3753 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3756 origin[1] += atof(Cmd_Argv(2));
3758 else if (!strcmp(Cmd_Argv(1), "movez"))
3760 if (Cmd_Argc() != 3)
3762 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3765 origin[2] += atof(Cmd_Argv(2));
3767 else if (!strcmp(Cmd_Argv(1), "angles"))
3769 if (Cmd_Argc() != 5)
3771 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3774 angles[0] = atof(Cmd_Argv(2));
3775 angles[1] = atof(Cmd_Argv(3));
3776 angles[2] = atof(Cmd_Argv(4));
3778 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3780 if (Cmd_Argc() != 3)
3782 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3785 angles[0] = atof(Cmd_Argv(2));
3787 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3789 if (Cmd_Argc() != 3)
3791 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3794 angles[1] = atof(Cmd_Argv(2));
3796 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3798 if (Cmd_Argc() != 3)
3800 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3803 angles[2] = atof(Cmd_Argv(2));
3805 else if (!strcmp(Cmd_Argv(1), "color"))
3807 if (Cmd_Argc() != 5)
3809 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3812 color[0] = atof(Cmd_Argv(2));
3813 color[1] = atof(Cmd_Argv(3));
3814 color[2] = atof(Cmd_Argv(4));
3816 else if (!strcmp(Cmd_Argv(1), "radius"))
3818 if (Cmd_Argc() != 3)
3820 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3823 radius = atof(Cmd_Argv(2));
3825 else if (!strcmp(Cmd_Argv(1), "style"))
3827 if (Cmd_Argc() != 3)
3829 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3832 style = atoi(Cmd_Argv(2));
3834 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3838 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3841 if (Cmd_Argc() == 3)
3842 strcpy(cubemapname, Cmd_Argv(2));
3846 else if (!strcmp(Cmd_Argv(1), "shadows"))
3848 if (Cmd_Argc() != 3)
3850 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3853 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3855 else if (!strcmp(Cmd_Argv(1), "corona"))
3857 if (Cmd_Argc() != 3)
3859 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3862 corona = atof(Cmd_Argv(2));
3864 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3866 if (Cmd_Argc() != 3)
3868 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3871 coronasizescale = atof(Cmd_Argv(2));
3873 else if (!strcmp(Cmd_Argv(1), "ambient"))
3875 if (Cmd_Argc() != 3)
3877 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3880 ambientscale = atof(Cmd_Argv(2));
3882 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3884 if (Cmd_Argc() != 3)
3886 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3889 diffusescale = atof(Cmd_Argv(2));
3891 else if (!strcmp(Cmd_Argv(1), "specular"))
3893 if (Cmd_Argc() != 3)
3895 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3898 specularscale = atof(Cmd_Argv(2));
3900 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3902 if (Cmd_Argc() != 3)
3904 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3907 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3909 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3911 if (Cmd_Argc() != 3)
3913 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3916 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3920 Con_Print("usage: r_editlights_edit [property] [value]\n");
3921 Con_Print("Selected light's properties:\n");
3922 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3923 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3924 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3925 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3926 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3927 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3928 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3929 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3930 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3931 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3932 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3933 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3934 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3935 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3938 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3939 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3942 void R_Shadow_EditLights_EditAll_f(void)
3946 if (!r_editlights.integer)
3948 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3952 for (light = r_shadow_worldlightchain;light;light = light->next)
3954 R_Shadow_SelectLight(light);
3955 R_Shadow_EditLights_Edit_f();
3959 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3961 int lightnumber, lightcount;
3965 if (!r_editlights.integer)
3971 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3972 if (light == r_shadow_selectedlight)
3973 lightnumber = lightcount;
3974 sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3975 if (r_shadow_selectedlight == NULL)
3977 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3978 sprintf(temp, "Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3979 sprintf(temp, "Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3980 sprintf(temp, "Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3981 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3982 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3983 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3984 sprintf(temp, "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3985 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3986 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3987 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3988 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3989 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3990 sprintf(temp, "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3991 sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3994 void R_Shadow_EditLights_ToggleShadow_f(void)
3996 if (!r_editlights.integer)
3998 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4001 if (!r_shadow_selectedlight)
4003 Con_Print("No selected light.\n");
4006 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
4009 void R_Shadow_EditLights_ToggleCorona_f(void)
4011 if (!r_editlights.integer)
4013 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4016 if (!r_shadow_selectedlight)
4018 Con_Print("No selected light.\n");
4021 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
4024 void R_Shadow_EditLights_Remove_f(void)
4026 if (!r_editlights.integer)
4028 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4031 if (!r_shadow_selectedlight)
4033 Con_Print("No selected light.\n");
4036 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4037 r_shadow_selectedlight = NULL;
4040 void R_Shadow_EditLights_Help_f(void)
4043 "Documentation on r_editlights system:\n"
4045 "r_editlights : enable/disable editing mode\n"
4046 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4047 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4048 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4049 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4050 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4051 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4052 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4054 "r_editlights_help : this help\n"
4055 "r_editlights_clear : remove all lights\n"
4056 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4057 "r_editlights_save : save to .rtlights file\n"
4058 "r_editlights_spawn : create a light with default settings\n"
4059 "r_editlights_edit command : edit selected light - more documentation below\n"
4060 "r_editlights_remove : remove selected light\n"
4061 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4062 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4063 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4065 "origin x y z : set light location\n"
4066 "originx x: set x component of light location\n"
4067 "originy y: set y component of light location\n"
4068 "originz z: set z component of light location\n"
4069 "move x y z : adjust light location\n"
4070 "movex x: adjust x component of light location\n"
4071 "movey y: adjust y component of light location\n"
4072 "movez z: adjust z component of light location\n"
4073 "angles x y z : set light angles\n"
4074 "anglesx x: set x component of light angles\n"
4075 "anglesy y: set y component of light angles\n"
4076 "anglesz z: set z component of light angles\n"
4077 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4078 "radius radius : set radius (size) of light\n"
4079 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4080 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4081 "shadows 1/0 : turn on/off shadows\n"
4082 "corona n : set corona intensity\n"
4083 "coronasize n : set corona size (0-1)\n"
4084 "ambient n : set ambient intensity (0-1)\n"
4085 "diffuse n : set diffuse intensity (0-1)\n"
4086 "specular n : set specular intensity (0-1)\n"
4087 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4088 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4089 "<nothing> : print light properties to console\n"
4093 void R_Shadow_EditLights_CopyInfo_f(void)
4095 if (!r_editlights.integer)
4097 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4100 if (!r_shadow_selectedlight)
4102 Con_Print("No selected light.\n");
4105 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4106 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4107 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4108 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4109 if (r_shadow_selectedlight->cubemapname)
4110 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4112 r_shadow_bufferlight.cubemapname[0] = 0;
4113 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4114 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4115 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4116 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4117 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4118 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4119 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4122 void R_Shadow_EditLights_PasteInfo_f(void)
4124 if (!r_editlights.integer)
4126 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4129 if (!r_shadow_selectedlight)
4131 Con_Print("No selected light.\n");
4134 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
4137 void R_Shadow_EditLights_Init(void)
4139 Cvar_RegisterVariable(&r_editlights);
4140 Cvar_RegisterVariable(&r_editlights_cursordistance);
4141 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4142 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4143 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4144 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4145 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4146 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4147 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4148 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4149 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4150 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4151 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4152 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4153 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4154 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4155 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4156 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4157 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4158 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4159 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4160 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);