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_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
160 rtexture_t *r_shadow_blankwhitecubetexture;
161 rtexture_t *r_shadow_blankblacktexture;
163 // lights are reloaded when this changes
164 char r_shadow_mapname[MAX_QPATH];
166 // used only for light filters (cubemaps)
167 rtexturepool_t *r_shadow_filters_texturepool;
169 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
170 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
171 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
172 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
173 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
174 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
175 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
176 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
177 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
178 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
179 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
180 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
181 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
182 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
183 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
184 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
185 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
186 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
187 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
188 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
189 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
190 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
191 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
192 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
193 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
194 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
195 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
196 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
197 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
198 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
199 cvar_t r_editlights = {0, "r_editlights", "0"};
200 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
201 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
202 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
203 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
204 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
205 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
206 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
208 float r_shadow_attenpower, r_shadow_attenscale;
210 rtlight_t *r_shadow_compilingrtlight;
211 dlight_t *r_shadow_worldlightchain;
212 dlight_t *r_shadow_selectedlight;
213 dlight_t r_shadow_bufferlight;
214 vec3_t r_editlights_cursorlocation;
216 rtexture_t *lighttextures[5];
218 extern int con_vislines;
220 typedef struct cubemapinfo_s
227 #define MAX_CUBEMAPS 256
228 static int numcubemaps;
229 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
231 #define SHADERPERMUTATION_SPECULAR (1<<0)
232 #define SHADERPERMUTATION_FOG (1<<1)
233 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
234 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
235 #define SHADERPERMUTATION_COUNT (1<<4)
237 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
239 void R_Shadow_UncompileWorldLights(void);
240 void R_Shadow_ClearWorldLights(void);
241 void R_Shadow_SaveWorldLights(void);
242 void R_Shadow_LoadWorldLights(void);
243 void R_Shadow_LoadLightsFile(void);
244 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
245 void R_Shadow_EditLights_Reload_f(void);
246 void R_Shadow_ValidateCvars(void);
247 static void R_Shadow_MakeTextures(void);
248 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
250 const char *builtinshader_light_vert =
251 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
252 "// written by Forest 'LordHavoc' Hale\n"
254 "uniform vec3 LightPosition;\n"
256 "varying vec2 TexCoord;\n"
257 "varying vec3 CubeVector;\n"
258 "varying vec3 LightVector;\n"
260 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
261 "uniform vec3 EyePosition;\n"
262 "varying vec3 EyeVector;\n"
265 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
269 " // copy the surface texcoord\n"
270 " TexCoord = gl_MultiTexCoord0.st;\n"
272 " // transform vertex position into light attenuation/cubemap space\n"
273 " // (-1 to +1 across the light box)\n"
274 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
276 " // transform unnormalized light direction into tangent space\n"
277 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
278 " // normalize it per pixel)\n"
279 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
280 " LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
281 " LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
282 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
284 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
285 " // transform unnormalized eye direction into tangent space\n"
286 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
287 " EyeVector.x = dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
288 " EyeVector.y = dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
289 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
292 " // transform vertex to camera space, using ftransform to match non-VS\n"
294 " gl_Position = ftransform();\n"
298 const char *builtinshader_light_frag =
299 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
300 "// written by Forest 'LordHavoc' Hale\n"
302 "uniform vec3 LightColor;\n"
304 "#ifdef USEOFFSETMAPPING\n"
305 "uniform float OffsetMapping_Scale;\n"
306 "uniform float OffsetMapping_Bias;\n"
308 "#ifdef USESPECULAR\n"
309 "uniform float SpecularPower;\n"
312 "uniform float FogRangeRecip;\n"
314 "uniform float AmbientScale;\n"
315 "uniform float DiffuseScale;\n"
316 "#ifdef USESPECULAR\n"
317 "uniform float SpecularScale;\n"
320 "uniform sampler2D Texture_Normal;\n"
321 "uniform sampler2D Texture_Color;\n"
322 "#ifdef USESPECULAR\n"
323 "uniform sampler2D Texture_Gloss;\n"
325 "#ifdef USECUBEFILTER\n"
326 "uniform samplerCube Texture_Cube;\n"
329 "uniform sampler2D Texture_FogMask;\n"
332 "varying vec2 TexCoord;\n"
333 "varying vec3 CubeVector;\n"
334 "varying vec3 LightVector;\n"
335 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
336 "varying vec3 EyeVector;\n"
343 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
344 " // center and sharp falloff at the edge, this is about the most efficient\n"
345 " // we can get away with as far as providing illumination.\n"
347 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
348 " // provide significant illumination, large = slow = pain.\n"
349 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
353 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
356 "#ifdef USEOFFSETMAPPING\n"
357 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
358 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
359 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
360 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
361 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
362 "#define TexCoord TexCoordOffset\n"
365 " // get the texels - with a blendmap we'd need to blend multiple here\n"
366 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
367 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
368 "#ifdef USESPECULAR\n"
369 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
372 " // calculate shading\n"
373 " vec3 diffusenormal = normalize(LightVector);\n"
374 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
375 "#ifdef USESPECULAR\n"
376 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
379 "#ifdef USECUBEFILTER\n"
380 " // apply light cubemap filter\n"
381 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
384 " // calculate fragment color\n"
385 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
389 void r_shadow_start(void)
392 // allocate vertex processing arrays
394 r_shadow_normalcubetexture = NULL;
395 r_shadow_attenuation2dtexture = NULL;
396 r_shadow_attenuation3dtexture = NULL;
397 r_shadow_blankbumptexture = NULL;
398 r_shadow_blankglosstexture = NULL;
399 r_shadow_blankwhitetexture = NULL;
400 r_shadow_blankwhitecubetexture = NULL;
401 r_shadow_blankblacktexture = NULL;
402 r_shadow_texturepool = NULL;
403 r_shadow_filters_texturepool = NULL;
404 R_Shadow_ValidateCvars();
405 R_Shadow_MakeTextures();
406 maxshadowelements = 0;
407 shadowelements = NULL;
415 shadowmarklist = NULL;
417 r_shadow_buffer_numclusterpvsbytes = 0;
418 r_shadow_buffer_clusterpvs = NULL;
419 r_shadow_buffer_clusterlist = NULL;
420 r_shadow_buffer_numsurfacepvsbytes = 0;
421 r_shadow_buffer_surfacepvs = NULL;
422 r_shadow_buffer_surfacelist = NULL;
423 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
424 r_shadow_program_light[i] = 0;
425 if (gl_support_fragment_shader)
427 char *vertstring, *fragstring;
428 int vertstrings_count;
429 int fragstrings_count;
430 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
431 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
432 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
433 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
434 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
436 vertstrings_count = 0;
437 fragstrings_count = 0;
438 if (i & SHADERPERMUTATION_SPECULAR)
440 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
441 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
443 if (i & SHADERPERMUTATION_FOG)
445 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
446 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
448 if (i & SHADERPERMUTATION_CUBEFILTER)
450 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
451 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
453 if (i & SHADERPERMUTATION_OFFSETMAPPING)
455 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
456 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
458 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
459 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
460 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
461 if (!r_shadow_program_light[i])
463 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");
466 qglUseProgramObjectARB(r_shadow_program_light[i]);
467 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
468 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
469 if (i & SHADERPERMUTATION_SPECULAR)
471 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
473 if (i & SHADERPERMUTATION_CUBEFILTER)
475 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
477 if (i & SHADERPERMUTATION_FOG)
479 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
482 qglUseProgramObjectARB(0);
484 Mem_Free(fragstring);
486 Mem_Free(vertstring);
490 void r_shadow_shutdown(void)
493 R_Shadow_UncompileWorldLights();
494 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
496 if (r_shadow_program_light[i])
498 GL_Backend_FreeProgram(r_shadow_program_light[i]);
499 r_shadow_program_light[i] = 0;
503 r_shadow_normalcubetexture = NULL;
504 r_shadow_attenuation2dtexture = NULL;
505 r_shadow_attenuation3dtexture = NULL;
506 r_shadow_blankbumptexture = NULL;
507 r_shadow_blankglosstexture = NULL;
508 r_shadow_blankwhitetexture = NULL;
509 r_shadow_blankwhitecubetexture = NULL;
510 r_shadow_blankblacktexture = NULL;
511 R_FreeTexturePool(&r_shadow_texturepool);
512 R_FreeTexturePool(&r_shadow_filters_texturepool);
513 maxshadowelements = 0;
515 Mem_Free(shadowelements);
516 shadowelements = NULL;
519 Mem_Free(vertexupdate);
522 Mem_Free(vertexremap);
528 Mem_Free(shadowmark);
531 Mem_Free(shadowmarklist);
532 shadowmarklist = NULL;
534 r_shadow_buffer_numclusterpvsbytes = 0;
535 if (r_shadow_buffer_clusterpvs)
536 Mem_Free(r_shadow_buffer_clusterpvs);
537 r_shadow_buffer_clusterpvs = NULL;
538 if (r_shadow_buffer_clusterlist)
539 Mem_Free(r_shadow_buffer_clusterlist);
540 r_shadow_buffer_clusterlist = NULL;
541 r_shadow_buffer_numsurfacepvsbytes = 0;
542 if (r_shadow_buffer_surfacepvs)
543 Mem_Free(r_shadow_buffer_surfacepvs);
544 r_shadow_buffer_surfacepvs = NULL;
545 if (r_shadow_buffer_surfacelist)
546 Mem_Free(r_shadow_buffer_surfacelist);
547 r_shadow_buffer_surfacelist = NULL;
550 void r_shadow_newmap(void)
554 void R_Shadow_Help_f(void)
557 "Documentation on r_shadow system:\n"
559 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
560 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
561 "r_shadow_debuglight : render only this light number (-1 = all)\n"
562 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
563 "r_shadow_gloss2intensity : brightness of forced gloss\n"
564 "r_shadow_glossintensity : brightness of textured gloss\n"
565 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
566 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
567 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
568 "r_shadow_portallight : use portal visibility for static light precomputation\n"
569 "r_shadow_projectdistance : shadow volume projection distance\n"
570 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
571 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
572 "r_shadow_realtime_world : use high quality world lighting mode\n"
573 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
574 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
575 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
576 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
577 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
578 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
579 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
580 "r_shadow_scissor : use scissor optimization\n"
581 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
582 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
583 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
584 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
585 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
587 "r_shadow_help : this help\n"
591 void R_Shadow_Init(void)
593 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
594 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
595 Cvar_RegisterVariable(&r_shadow_cull);
596 Cvar_RegisterVariable(&r_shadow_debuglight);
597 Cvar_RegisterVariable(&r_shadow_gloss);
598 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
599 Cvar_RegisterVariable(&r_shadow_glossintensity);
600 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
601 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
602 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
603 Cvar_RegisterVariable(&r_shadow_portallight);
604 Cvar_RegisterVariable(&r_shadow_projectdistance);
605 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
606 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
607 Cvar_RegisterVariable(&r_shadow_realtime_world);
608 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
609 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
610 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
611 Cvar_RegisterVariable(&r_shadow_scissor);
612 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
613 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
614 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
615 Cvar_RegisterVariable(&r_shadow_staticworldlights);
616 Cvar_RegisterVariable(&r_shadow_texture3d);
617 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
618 Cvar_RegisterVariable(&r_shadow_glsl);
619 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
620 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
621 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
622 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
623 if (gamemode == GAME_TENEBRAE)
625 Cvar_SetValue("r_shadow_gloss", 2);
626 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
628 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
629 R_Shadow_EditLights_Init();
630 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
631 r_shadow_worldlightchain = NULL;
632 maxshadowelements = 0;
633 shadowelements = NULL;
641 shadowmarklist = NULL;
643 r_shadow_buffer_numclusterpvsbytes = 0;
644 r_shadow_buffer_clusterpvs = NULL;
645 r_shadow_buffer_clusterlist = NULL;
646 r_shadow_buffer_numsurfacepvsbytes = 0;
647 r_shadow_buffer_surfacepvs = NULL;
648 r_shadow_buffer_surfacelist = NULL;
649 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
652 matrix4x4_t matrix_attenuationxyz =
655 {0.5, 0.0, 0.0, 0.5},
656 {0.0, 0.5, 0.0, 0.5},
657 {0.0, 0.0, 0.5, 0.5},
662 matrix4x4_t matrix_attenuationz =
665 {0.0, 0.0, 0.5, 0.5},
666 {0.0, 0.0, 0.0, 0.5},
667 {0.0, 0.0, 0.0, 0.5},
672 int *R_Shadow_ResizeShadowElements(int numtris)
674 // make sure shadowelements is big enough for this volume
675 if (maxshadowelements < numtris * 24)
677 maxshadowelements = numtris * 24;
679 Mem_Free(shadowelements);
680 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
682 return shadowelements;
685 void R_Shadow_EnlargeClusterBuffer(int numclusters)
687 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
688 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
690 if (r_shadow_buffer_clusterpvs)
691 Mem_Free(r_shadow_buffer_clusterpvs);
692 if (r_shadow_buffer_clusterlist)
693 Mem_Free(r_shadow_buffer_clusterlist);
694 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
695 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
696 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
700 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
702 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
703 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
705 if (r_shadow_buffer_surfacepvs)
706 Mem_Free(r_shadow_buffer_surfacepvs);
707 if (r_shadow_buffer_surfacelist)
708 Mem_Free(r_shadow_buffer_surfacelist);
709 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
710 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
711 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
715 void R_Shadow_PrepareShadowMark(int numtris)
717 // make sure shadowmark is big enough for this volume
718 if (maxshadowmark < numtris)
720 maxshadowmark = numtris;
722 Mem_Free(shadowmark);
724 Mem_Free(shadowmarklist);
725 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
726 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
730 // if shadowmarkcount wrapped we clear the array and adjust accordingly
731 if (shadowmarkcount == 0)
734 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
739 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)
742 int outtriangles = 0, outvertices = 0;
746 if (maxvertexupdate < innumvertices)
748 maxvertexupdate = innumvertices;
750 Mem_Free(vertexupdate);
752 Mem_Free(vertexremap);
753 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
754 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
758 if (vertexupdatenum == 0)
761 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
762 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
765 for (i = 0;i < numshadowmarktris;i++)
766 shadowmark[shadowmarktris[i]] = shadowmarkcount;
768 for (i = 0;i < numshadowmarktris;i++)
770 element = inelement3i + shadowmarktris[i] * 3;
771 // make sure the vertices are created
772 for (j = 0;j < 3;j++)
774 if (vertexupdate[element[j]] != vertexupdatenum)
776 float ratio, direction[3];
777 vertexupdate[element[j]] = vertexupdatenum;
778 vertexremap[element[j]] = outvertices;
779 vertex = invertex3f + element[j] * 3;
780 // project one copy of the vertex to the sphere radius of the light
781 // (FIXME: would projecting it to the light box be better?)
782 VectorSubtract(vertex, projectorigin, direction);
783 ratio = projectdistance / VectorLength(direction);
784 VectorCopy(vertex, outvertex3f);
785 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
792 for (i = 0;i < numshadowmarktris;i++)
794 int remappedelement[3];
796 const int *neighbortriangle;
798 markindex = shadowmarktris[i] * 3;
799 element = inelement3i + markindex;
800 neighbortriangle = inneighbor3i + markindex;
801 // output the front and back triangles
802 outelement3i[0] = vertexremap[element[0]];
803 outelement3i[1] = vertexremap[element[1]];
804 outelement3i[2] = vertexremap[element[2]];
805 outelement3i[3] = vertexremap[element[2]] + 1;
806 outelement3i[4] = vertexremap[element[1]] + 1;
807 outelement3i[5] = vertexremap[element[0]] + 1;
811 // output the sides (facing outward from this triangle)
812 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
814 remappedelement[0] = vertexremap[element[0]];
815 remappedelement[1] = vertexremap[element[1]];
816 outelement3i[0] = remappedelement[1];
817 outelement3i[1] = remappedelement[0];
818 outelement3i[2] = remappedelement[0] + 1;
819 outelement3i[3] = remappedelement[1];
820 outelement3i[4] = remappedelement[0] + 1;
821 outelement3i[5] = remappedelement[1] + 1;
826 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
828 remappedelement[1] = vertexremap[element[1]];
829 remappedelement[2] = vertexremap[element[2]];
830 outelement3i[0] = remappedelement[2];
831 outelement3i[1] = remappedelement[1];
832 outelement3i[2] = remappedelement[1] + 1;
833 outelement3i[3] = remappedelement[2];
834 outelement3i[4] = remappedelement[1] + 1;
835 outelement3i[5] = remappedelement[2] + 1;
840 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
842 remappedelement[0] = vertexremap[element[0]];
843 remappedelement[2] = vertexremap[element[2]];
844 outelement3i[0] = remappedelement[0];
845 outelement3i[1] = remappedelement[2];
846 outelement3i[2] = remappedelement[2] + 1;
847 outelement3i[3] = remappedelement[0];
848 outelement3i[4] = remappedelement[2] + 1;
849 outelement3i[5] = remappedelement[0] + 1;
856 *outnumvertices = outvertices;
860 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)
863 if (projectdistance < 0.1)
865 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
868 if (!numverts || !nummarktris)
870 // make sure shadowelements is big enough for this volume
871 if (maxshadowelements < nummarktris * 24)
872 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
873 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
874 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
877 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)
882 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
884 tend = firsttriangle + numtris;
885 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
886 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
887 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
889 // surface box entirely inside light box, no box cull
890 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
891 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
892 shadowmarklist[numshadowmark++] = t;
896 // surface box not entirely inside light box, cull each triangle
897 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
899 v[0] = invertex3f + e[0] * 3;
900 v[1] = invertex3f + e[1] * 3;
901 v[2] = invertex3f + e[2] * 3;
902 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
903 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
904 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
905 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
906 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
907 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
908 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
909 shadowmarklist[numshadowmark++] = t;
914 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
917 if (r_shadow_compilingrtlight)
919 // if we're compiling an rtlight, capture the mesh
920 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
923 memset(&m, 0, sizeof(m));
924 m.pointer_vertex = vertex3f;
926 GL_LockArrays(0, numvertices);
927 if (r_shadowstage == SHADOWSTAGE_STENCIL)
929 // increment stencil if backface is behind depthbuffer
930 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
931 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
932 R_Mesh_Draw(numvertices, numtriangles, element3i);
934 c_rt_shadowtris += numtriangles;
935 // decrement stencil if frontface is behind depthbuffer
936 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
937 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
939 R_Mesh_Draw(numvertices, numtriangles, element3i);
941 c_rt_shadowtris += numtriangles;
945 static void R_Shadow_MakeTextures(void)
947 int x, y, z, d, side;
948 float v[3], s, t, intensity;
950 R_FreeTexturePool(&r_shadow_texturepool);
951 r_shadow_texturepool = R_AllocTexturePool();
952 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
953 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
955 #define ATTEN2DSIZE 64
956 #define ATTEN3DSIZE 32
957 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
958 data[0] = 128; // normal X
959 data[1] = 128; // normal Y
960 data[2] = 255; // normal Z
961 data[3] = 128; // height
962 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
967 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
972 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
977 r_shadow_blankblacktexture = R_LoadTexture2D(r_shadow_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
978 r_shadow_blankwhitecubetexture = NULL;
979 r_shadow_normalcubetexture = NULL;
980 if (gl_texturecubemap)
982 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
983 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
984 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
985 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
986 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
987 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
988 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
989 for (side = 0;side < 6;side++)
991 for (y = 0;y < NORMSIZE;y++)
993 for (x = 0;x < NORMSIZE;x++)
995 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
996 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1030 intensity = 127.0f / sqrt(DotProduct(v, v));
1031 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1032 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1033 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1034 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1038 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1040 for (y = 0;y < ATTEN2DSIZE;y++)
1042 for (x = 0;x < ATTEN2DSIZE;x++)
1044 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1045 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1047 intensity = 1.0f - sqrt(DotProduct(v, v));
1049 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1050 d = bound(0, intensity, 255);
1051 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1052 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1053 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1054 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1057 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1058 if (r_shadow_texture3d.integer)
1060 for (z = 0;z < ATTEN3DSIZE;z++)
1062 for (y = 0;y < ATTEN3DSIZE;y++)
1064 for (x = 0;x < ATTEN3DSIZE;x++)
1066 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1067 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1068 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1069 intensity = 1.0f - sqrt(DotProduct(v, v));
1071 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1072 d = bound(0, intensity, 255);
1073 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1074 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1075 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1076 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1080 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1085 void R_Shadow_ValidateCvars(void)
1087 if (r_shadow_texture3d.integer && !gl_texture3d)
1088 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1089 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1090 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1093 void R_Shadow_Stage_Begin(void)
1097 R_Shadow_ValidateCvars();
1099 if (!r_shadow_attenuation2dtexture
1100 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1101 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1102 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1103 R_Shadow_MakeTextures();
1105 memset(&m, 0, sizeof(m));
1106 GL_BlendFunc(GL_ONE, GL_ZERO);
1107 GL_DepthMask(false);
1110 GL_Color(0, 0, 0, 1);
1111 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1112 qglEnable(GL_CULL_FACE);
1113 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1114 r_shadowstage = SHADOWSTAGE_NONE;
1117 void R_Shadow_Stage_ShadowVolumes(void)
1120 memset(&m, 0, sizeof(m));
1122 GL_Color(1, 1, 1, 1);
1123 GL_ColorMask(0, 0, 0, 0);
1124 GL_BlendFunc(GL_ONE, GL_ZERO);
1125 GL_DepthMask(false);
1127 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1128 //if (r_shadow_shadow_polygonoffset.value != 0)
1130 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1131 // qglEnable(GL_POLYGON_OFFSET_FILL);
1134 // qglDisable(GL_POLYGON_OFFSET_FILL);
1135 qglDepthFunc(GL_LESS);
1136 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1137 qglEnable(GL_STENCIL_TEST);
1138 qglStencilFunc(GL_ALWAYS, 128, ~0);
1139 if (gl_ext_stenciltwoside.integer)
1141 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1142 qglDisable(GL_CULL_FACE);
1143 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1144 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1146 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1147 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1149 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1153 r_shadowstage = SHADOWSTAGE_STENCIL;
1154 qglEnable(GL_CULL_FACE);
1156 // this is changed by every shadow render so its value here is unimportant
1157 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1159 GL_Clear(GL_STENCIL_BUFFER_BIT);
1161 // LordHavoc note: many shadow volumes reside entirely inside the world
1162 // (that is to say they are entirely bounded by their lit surfaces),
1163 // which can be optimized by handling things as an inverted light volume,
1164 // with the shadow boundaries of the world being simulated by an altered
1165 // (129) bias to stencil clearing on such lights
1166 // FIXME: generate inverted light volumes for use as shadow volumes and
1167 // optimize for them as noted above
1170 void R_Shadow_Stage_Light(int shadowtest)
1173 memset(&m, 0, sizeof(m));
1175 GL_BlendFunc(GL_ONE, GL_ONE);
1176 GL_DepthMask(false);
1178 qglPolygonOffset(0, 0);
1179 //qglDisable(GL_POLYGON_OFFSET_FILL);
1180 GL_Color(1, 1, 1, 1);
1181 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1182 qglDepthFunc(GL_EQUAL);
1183 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1184 qglEnable(GL_CULL_FACE);
1186 qglEnable(GL_STENCIL_TEST);
1188 qglDisable(GL_STENCIL_TEST);
1189 if (gl_support_stenciltwoside)
1190 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1192 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1193 // only draw light where this geometry was already rendered AND the
1194 // stencil is 128 (values other than this mean shadow)
1195 qglStencilFunc(GL_EQUAL, 128, ~0);
1196 r_shadowstage = SHADOWSTAGE_LIGHT;
1200 void R_Shadow_Stage_End(void)
1203 memset(&m, 0, sizeof(m));
1205 GL_BlendFunc(GL_ONE, GL_ZERO);
1208 qglPolygonOffset(0, 0);
1209 //qglDisable(GL_POLYGON_OFFSET_FILL);
1210 GL_Color(1, 1, 1, 1);
1211 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1212 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1213 qglDepthFunc(GL_LEQUAL);
1214 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1215 qglDisable(GL_STENCIL_TEST);
1216 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1217 if (gl_support_stenciltwoside)
1218 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1220 qglStencilFunc(GL_ALWAYS, 128, ~0);
1221 r_shadowstage = SHADOWSTAGE_NONE;
1224 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1226 int i, ix1, iy1, ix2, iy2;
1227 float x1, y1, x2, y2, x, y, f;
1228 vec3_t smins, smaxs;
1230 if (!r_shadow_scissor.integer)
1232 // if view is inside the box, just say yes it's visible
1233 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1235 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1238 for (i = 0;i < 3;i++)
1240 if (r_viewforward[i] >= 0)
1251 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1252 if (DotProduct(r_viewforward, v2) <= f)
1254 // entirely behind nearclip plane
1257 if (DotProduct(r_viewforward, v) >= f)
1259 // entirely infront of nearclip plane
1260 x1 = y1 = x2 = y2 = 0;
1261 for (i = 0;i < 8;i++)
1263 v[0] = (i & 1) ? mins[0] : maxs[0];
1264 v[1] = (i & 2) ? mins[1] : maxs[1];
1265 v[2] = (i & 4) ? mins[2] : maxs[2];
1267 GL_TransformToScreen(v, v2);
1268 //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]);
1287 // clipped by nearclip plane
1288 // this is nasty and crude...
1289 // create viewspace bbox
1290 for (i = 0;i < 8;i++)
1292 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1293 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1294 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1295 v2[0] = -DotProduct(v, r_viewleft);
1296 v2[1] = DotProduct(v, r_viewup);
1297 v2[2] = DotProduct(v, r_viewforward);
1300 if (smins[0] > v2[0]) smins[0] = v2[0];
1301 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1302 if (smins[1] > v2[1]) smins[1] = v2[1];
1303 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1304 if (smins[2] > v2[2]) smins[2] = v2[2];
1305 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1309 smins[0] = smaxs[0] = v2[0];
1310 smins[1] = smaxs[1] = v2[1];
1311 smins[2] = smaxs[2] = v2[2];
1314 // now we have a bbox in viewspace
1315 // clip it to the view plane
1318 // return true if that culled the box
1319 if (smins[2] >= smaxs[2])
1321 // ok some of it is infront of the view, transform each corner back to
1322 // worldspace and then to screenspace and make screen rect
1323 // initialize these variables just to avoid compiler warnings
1324 x1 = y1 = x2 = y2 = 0;
1325 for (i = 0;i < 8;i++)
1327 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1328 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1329 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1330 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1331 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1332 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1334 GL_TransformToScreen(v, v2);
1335 //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]);
1352 // this code doesn't handle boxes with any points behind view properly
1353 x1 = 1000;x2 = -1000;
1354 y1 = 1000;y2 = -1000;
1355 for (i = 0;i < 8;i++)
1357 v[0] = (i & 1) ? mins[0] : maxs[0];
1358 v[1] = (i & 2) ? mins[1] : maxs[1];
1359 v[2] = (i & 4) ? mins[2] : maxs[2];
1361 GL_TransformToScreen(v, v2);
1362 //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]);
1380 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1381 if (ix1 < r_view_x) ix1 = r_view_x;
1382 if (iy1 < r_view_y) iy1 = r_view_y;
1383 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1384 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1385 if (ix2 <= ix1 || iy2 <= iy1)
1387 // set up the scissor rectangle
1388 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1389 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1390 //qglEnable(GL_SCISSOR_TEST);
1395 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1397 float *color4f = varray_color4f;
1398 float dist, dot, intensity, v[3], n[3];
1399 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1401 Matrix4x4_Transform(m, vertex3f, v);
1402 if ((dist = DotProduct(v, v)) < 1)
1404 Matrix4x4_Transform3x3(m, normal3f, n);
1405 if ((dot = DotProduct(n, v)) > 0)
1408 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1409 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1410 VectorScale(lightcolor, intensity, color4f);
1415 VectorClear(color4f);
1421 VectorClear(color4f);
1427 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1429 float *color4f = varray_color4f;
1430 float dist, dot, intensity, v[3], n[3];
1431 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1433 Matrix4x4_Transform(m, vertex3f, v);
1434 if ((dist = fabs(v[2])) < 1)
1436 Matrix4x4_Transform3x3(m, normal3f, n);
1437 if ((dot = DotProduct(n, v)) > 0)
1439 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1440 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1441 VectorScale(lightcolor, intensity, color4f);
1446 VectorClear(color4f);
1452 VectorClear(color4f);
1458 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1460 float *color4f = varray_color4f;
1461 float dot, intensity, v[3], n[3];
1462 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1464 Matrix4x4_Transform(m, vertex3f, v);
1465 Matrix4x4_Transform3x3(m, normal3f, n);
1466 if ((dot = DotProduct(n, v)) > 0)
1468 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1469 VectorScale(lightcolor, intensity, color4f);
1474 VectorClear(color4f);
1480 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1482 float *color4f = varray_color4f;
1483 float dist, intensity, v[3];
1484 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1486 Matrix4x4_Transform(m, vertex3f, v);
1487 if ((dist = DotProduct(v, v)) < 1)
1490 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1491 VectorScale(lightcolor, intensity, color4f);
1496 VectorClear(color4f);
1502 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1504 float *color4f = varray_color4f;
1505 float dist, intensity, v[3];
1506 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1508 Matrix4x4_Transform(m, vertex3f, v);
1509 if ((dist = fabs(v[2])) < 1)
1511 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1512 VectorScale(lightcolor, intensity, color4f);
1517 VectorClear(color4f);
1523 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1524 #define USETEXMATRIX
1526 #ifndef USETEXMATRIX
1527 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1528 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1529 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1533 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1534 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1535 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1542 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1546 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1547 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1555 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)
1559 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1561 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1562 // the cubemap normalizes this for us
1563 out3f[0] = DotProduct(svector3f, lightdir);
1564 out3f[1] = DotProduct(tvector3f, lightdir);
1565 out3f[2] = DotProduct(normal3f, lightdir);
1569 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)
1572 float lightdir[3], eyedir[3], halfdir[3];
1573 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1575 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1576 VectorNormalizeFast(lightdir);
1577 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1578 VectorNormalizeFast(eyedir);
1579 VectorAdd(lightdir, eyedir, halfdir);
1580 // the cubemap normalizes this for us
1581 out3f[0] = DotProduct(svector3f, halfdir);
1582 out3f[1] = DotProduct(tvector3f, halfdir);
1583 out3f[2] = DotProduct(normal3f, halfdir);
1587 void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
1590 float color[3], color2[3], colorscale;
1592 // FIXME: support EF_NODEPTHTEST
1593 GL_DepthMask(false);
1596 bumptexture = r_shadow_blankbumptexture;
1597 specularscale *= r_shadow_glossintensity.value;
1600 if (r_shadow_gloss.integer >= 2)
1602 glosstexture = r_shadow_blankglosstexture;
1603 specularscale *= r_shadow_gloss2intensity.value;
1607 glosstexture = r_shadow_blankblacktexture;
1611 if (r_shadow_gloss.integer < 1)
1614 lightcubemap = r_shadow_blankwhitecubetexture;
1615 if (ambientscale + diffusescale + specularscale < 0.01)
1617 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1619 unsigned int perm, prog;
1620 // GLSL shader path (GFFX5200, Radeon 9500)
1621 memset(&m, 0, sizeof(m));
1622 m.pointer_vertex = vertex3f;
1623 m.pointer_texcoord[0] = texcoord2f;
1624 m.pointer_texcoord3f[1] = svector3f;
1625 m.pointer_texcoord3f[2] = tvector3f;
1626 m.pointer_texcoord3f[3] = normal3f;
1627 m.tex[0] = R_GetTexture(bumptexture);
1628 m.tex[1] = R_GetTexture(basetexture);
1629 m.tex[2] = R_GetTexture(glosstexture);
1630 m.texcubemap[3] = R_GetTexture(lightcubemap);
1631 // TODO: support fog (after renderer is converted to texture fog)
1632 m.tex[4] = R_GetTexture(r_shadow_blankwhitetexture);
1633 m.texmatrix[3] = *matrix_modeltolight;
1635 GL_BlendFunc(GL_ONE, GL_ONE);
1636 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1639 // only add a feature to the permutation if that permutation exists
1640 // (otherwise it might end up not using a shader at all, which looks
1641 // worse than using less features)
1642 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1643 perm |= SHADERPERMUTATION_SPECULAR;
1644 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1645 // perm |= SHADERPERMUTATION_FOG;
1646 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1647 perm |= SHADERPERMUTATION_CUBEFILTER;
1648 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1649 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1650 prog = r_shadow_program_light[perm];
1651 qglUseProgramObjectARB(prog);CHECKGLERROR
1652 // TODO: support fog (after renderer is converted to texture fog)
1653 if (perm & SHADERPERMUTATION_FOG)
1655 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1657 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1658 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1659 if (perm & SHADERPERMUTATION_SPECULAR)
1661 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1662 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1664 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);CHECKGLERROR
1665 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1666 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1668 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1670 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1672 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1673 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1676 GL_LockArrays(0, numverts);
1677 R_Mesh_Draw(numverts, numtriangles, elements);
1679 c_rt_lighttris += numtriangles;
1680 GL_LockArrays(0, 0);
1681 qglUseProgramObjectARB(0);
1682 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1683 qglBegin(GL_TRIANGLES);
1687 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1690 bumptexture = r_shadow_blankbumptexture;
1692 glosstexture = r_shadow_blankglosstexture;
1696 colorscale = ambientscale;
1697 // colorscale accounts for how much we multiply the brightness
1700 // mult is how many times the final pass of the lighting will be
1701 // performed to get more brightness than otherwise possible.
1703 // Limit mult to 64 for sanity sake.
1704 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1706 // 3 3D combine path (Geforce3, Radeon 8500)
1707 memset(&m, 0, sizeof(m));
1708 m.pointer_vertex = vertex3f;
1709 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1711 m.pointer_texcoord3f[0] = vertex3f;
1712 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1714 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1715 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1717 m.tex[1] = R_GetTexture(basetexture);
1718 m.pointer_texcoord[1] = texcoord2f;
1719 m.texcubemap[2] = R_GetTexture(lightcubemap);
1721 m.pointer_texcoord3f[2] = vertex3f;
1722 m.texmatrix[2] = *matrix_modeltolight;
1724 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1725 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1727 GL_BlendFunc(GL_ONE, GL_ONE);
1729 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1731 // 2 3D combine path (Geforce3, original Radeon)
1732 memset(&m, 0, sizeof(m));
1733 m.pointer_vertex = vertex3f;
1734 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1736 m.pointer_texcoord3f[0] = vertex3f;
1737 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1739 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1740 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1742 m.tex[1] = R_GetTexture(basetexture);
1743 m.pointer_texcoord[1] = texcoord2f;
1744 GL_BlendFunc(GL_ONE, GL_ONE);
1746 else if (r_textureunits.integer >= 4 && lightcubemap)
1748 // 4 2D combine path (Geforce3, Radeon 8500)
1749 memset(&m, 0, sizeof(m));
1750 m.pointer_vertex = vertex3f;
1751 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1753 m.pointer_texcoord3f[0] = vertex3f;
1754 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1756 m.pointer_texcoord[0] = varray_texcoord2f[0];
1757 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1759 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1761 m.pointer_texcoord3f[1] = vertex3f;
1762 m.texmatrix[1] = *matrix_modeltoattenuationz;
1764 m.pointer_texcoord[1] = varray_texcoord2f[1];
1765 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1767 m.tex[2] = R_GetTexture(basetexture);
1768 m.pointer_texcoord[2] = texcoord2f;
1771 m.texcubemap[3] = R_GetTexture(lightcubemap);
1773 m.pointer_texcoord3f[3] = vertex3f;
1774 m.texmatrix[3] = *matrix_modeltolight;
1776 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1777 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1780 GL_BlendFunc(GL_ONE, GL_ONE);
1782 else if (r_textureunits.integer >= 3 && !lightcubemap)
1784 // 3 2D combine path (Geforce3, original Radeon)
1785 memset(&m, 0, sizeof(m));
1786 m.pointer_vertex = vertex3f;
1787 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1789 m.pointer_texcoord3f[0] = vertex3f;
1790 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1792 m.pointer_texcoord[0] = varray_texcoord2f[0];
1793 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1795 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1797 m.pointer_texcoord3f[1] = vertex3f;
1798 m.texmatrix[1] = *matrix_modeltoattenuationz;
1800 m.pointer_texcoord[1] = varray_texcoord2f[1];
1801 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1803 m.tex[2] = R_GetTexture(basetexture);
1804 m.pointer_texcoord[2] = texcoord2f;
1805 GL_BlendFunc(GL_ONE, GL_ONE);
1809 // 2/2/2 2D combine path (any dot3 card)
1810 memset(&m, 0, sizeof(m));
1811 m.pointer_vertex = vertex3f;
1812 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1814 m.pointer_texcoord3f[0] = vertex3f;
1815 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1817 m.pointer_texcoord[0] = varray_texcoord2f[0];
1818 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1820 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1822 m.pointer_texcoord3f[1] = vertex3f;
1823 m.texmatrix[1] = *matrix_modeltoattenuationz;
1825 m.pointer_texcoord[1] = varray_texcoord2f[1];
1826 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1829 GL_ColorMask(0,0,0,1);
1830 GL_BlendFunc(GL_ONE, GL_ZERO);
1831 GL_LockArrays(0, numverts);
1832 R_Mesh_Draw(numverts, numtriangles, elements);
1833 GL_LockArrays(0, 0);
1835 c_rt_lighttris += numtriangles;
1837 memset(&m, 0, sizeof(m));
1838 m.pointer_vertex = vertex3f;
1839 m.tex[0] = R_GetTexture(basetexture);
1840 m.pointer_texcoord[0] = texcoord2f;
1843 m.texcubemap[1] = R_GetTexture(lightcubemap);
1845 m.pointer_texcoord3f[1] = vertex3f;
1846 m.texmatrix[1] = *matrix_modeltolight;
1848 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1849 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1852 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1854 // this final code is shared
1856 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1857 VectorScale(lightcolor, colorscale, color2);
1858 GL_LockArrays(0, numverts);
1859 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1861 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1862 R_Mesh_Draw(numverts, numtriangles, elements);
1864 c_rt_lighttris += numtriangles;
1866 GL_LockArrays(0, 0);
1871 colorscale = diffusescale;
1872 // colorscale accounts for how much we multiply the brightness
1875 // mult is how many times the final pass of the lighting will be
1876 // performed to get more brightness than otherwise possible.
1878 // Limit mult to 64 for sanity sake.
1879 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1881 // 3/2 3D combine path (Geforce3, Radeon 8500)
1882 memset(&m, 0, sizeof(m));
1883 m.pointer_vertex = vertex3f;
1884 m.tex[0] = R_GetTexture(bumptexture);
1885 m.texcombinergb[0] = GL_REPLACE;
1886 m.pointer_texcoord[0] = texcoord2f;
1887 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1888 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1889 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1890 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1891 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1893 m.pointer_texcoord3f[2] = vertex3f;
1894 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1896 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1897 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1900 GL_ColorMask(0,0,0,1);
1901 GL_BlendFunc(GL_ONE, GL_ZERO);
1902 GL_LockArrays(0, numverts);
1903 R_Mesh_Draw(numverts, numtriangles, elements);
1904 GL_LockArrays(0, 0);
1906 c_rt_lighttris += numtriangles;
1908 memset(&m, 0, sizeof(m));
1909 m.pointer_vertex = vertex3f;
1910 m.tex[0] = R_GetTexture(basetexture);
1911 m.pointer_texcoord[0] = texcoord2f;
1914 m.texcubemap[1] = R_GetTexture(lightcubemap);
1916 m.pointer_texcoord3f[1] = vertex3f;
1917 m.texmatrix[1] = *matrix_modeltolight;
1919 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1920 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1923 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1925 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1927 // 1/2/2 3D combine path (original Radeon)
1928 memset(&m, 0, sizeof(m));
1929 m.pointer_vertex = vertex3f;
1930 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1932 m.pointer_texcoord3f[0] = vertex3f;
1933 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1935 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1936 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1939 GL_ColorMask(0,0,0,1);
1940 GL_BlendFunc(GL_ONE, GL_ZERO);
1941 GL_LockArrays(0, numverts);
1942 R_Mesh_Draw(numverts, numtriangles, elements);
1943 GL_LockArrays(0, 0);
1945 c_rt_lighttris += numtriangles;
1947 memset(&m, 0, sizeof(m));
1948 m.pointer_vertex = vertex3f;
1949 m.tex[0] = R_GetTexture(bumptexture);
1950 m.texcombinergb[0] = GL_REPLACE;
1951 m.pointer_texcoord[0] = texcoord2f;
1952 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1953 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1954 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1955 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1957 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1958 GL_LockArrays(0, numverts);
1959 R_Mesh_Draw(numverts, numtriangles, elements);
1960 GL_LockArrays(0, 0);
1962 c_rt_lighttris += numtriangles;
1964 memset(&m, 0, sizeof(m));
1965 m.pointer_vertex = vertex3f;
1966 m.tex[0] = R_GetTexture(basetexture);
1967 m.pointer_texcoord[0] = texcoord2f;
1970 m.texcubemap[1] = R_GetTexture(lightcubemap);
1972 m.pointer_texcoord3f[1] = vertex3f;
1973 m.texmatrix[1] = *matrix_modeltolight;
1975 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1976 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1979 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1981 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1983 // 2/2 3D combine path (original Radeon)
1984 memset(&m, 0, sizeof(m));
1985 m.pointer_vertex = vertex3f;
1986 m.tex[0] = R_GetTexture(bumptexture);
1987 m.texcombinergb[0] = GL_REPLACE;
1988 m.pointer_texcoord[0] = texcoord2f;
1989 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1990 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1991 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1992 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1994 GL_ColorMask(0,0,0,1);
1995 GL_BlendFunc(GL_ONE, GL_ZERO);
1996 GL_LockArrays(0, numverts);
1997 R_Mesh_Draw(numverts, numtriangles, elements);
1998 GL_LockArrays(0, 0);
2000 c_rt_lighttris += numtriangles;
2002 memset(&m, 0, sizeof(m));
2003 m.pointer_vertex = vertex3f;
2004 m.tex[0] = R_GetTexture(basetexture);
2005 m.pointer_texcoord[0] = texcoord2f;
2006 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2008 m.pointer_texcoord3f[1] = vertex3f;
2009 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2011 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2012 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2014 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2016 else if (r_textureunits.integer >= 4)
2018 // 4/2 2D combine path (Geforce3, Radeon 8500)
2019 memset(&m, 0, sizeof(m));
2020 m.pointer_vertex = vertex3f;
2021 m.tex[0] = R_GetTexture(bumptexture);
2022 m.texcombinergb[0] = GL_REPLACE;
2023 m.pointer_texcoord[0] = texcoord2f;
2024 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2025 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2026 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2027 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2028 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2030 m.pointer_texcoord3f[2] = vertex3f;
2031 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2033 m.pointer_texcoord[2] = varray_texcoord2f[2];
2034 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2036 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2038 m.pointer_texcoord3f[3] = vertex3f;
2039 m.texmatrix[3] = *matrix_modeltoattenuationz;
2041 m.pointer_texcoord[3] = varray_texcoord2f[3];
2042 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2045 GL_ColorMask(0,0,0,1);
2046 GL_BlendFunc(GL_ONE, GL_ZERO);
2047 GL_LockArrays(0, numverts);
2048 R_Mesh_Draw(numverts, numtriangles, elements);
2049 GL_LockArrays(0, 0);
2051 c_rt_lighttris += numtriangles;
2053 memset(&m, 0, sizeof(m));
2054 m.pointer_vertex = vertex3f;
2055 m.tex[0] = R_GetTexture(basetexture);
2056 m.pointer_texcoord[0] = texcoord2f;
2059 m.texcubemap[1] = R_GetTexture(lightcubemap);
2061 m.pointer_texcoord3f[1] = vertex3f;
2062 m.texmatrix[1] = *matrix_modeltolight;
2064 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2065 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2068 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2072 // 2/2/2 2D combine path (any dot3 card)
2073 memset(&m, 0, sizeof(m));
2074 m.pointer_vertex = vertex3f;
2075 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2077 m.pointer_texcoord3f[0] = vertex3f;
2078 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2080 m.pointer_texcoord[0] = varray_texcoord2f[0];
2081 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2083 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2085 m.pointer_texcoord3f[1] = vertex3f;
2086 m.texmatrix[1] = *matrix_modeltoattenuationz;
2088 m.pointer_texcoord[1] = varray_texcoord2f[1];
2089 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2092 GL_ColorMask(0,0,0,1);
2093 GL_BlendFunc(GL_ONE, GL_ZERO);
2094 GL_LockArrays(0, numverts);
2095 R_Mesh_Draw(numverts, numtriangles, elements);
2096 GL_LockArrays(0, 0);
2098 c_rt_lighttris += numtriangles;
2100 memset(&m, 0, sizeof(m));
2101 m.pointer_vertex = vertex3f;
2102 m.tex[0] = R_GetTexture(bumptexture);
2103 m.texcombinergb[0] = GL_REPLACE;
2104 m.pointer_texcoord[0] = texcoord2f;
2105 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2106 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2107 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2108 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2110 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2111 GL_LockArrays(0, numverts);
2112 R_Mesh_Draw(numverts, numtriangles, elements);
2113 GL_LockArrays(0, 0);
2115 c_rt_lighttris += numtriangles;
2117 memset(&m, 0, sizeof(m));
2118 m.pointer_vertex = vertex3f;
2119 m.tex[0] = R_GetTexture(basetexture);
2120 m.pointer_texcoord[0] = texcoord2f;
2123 m.texcubemap[1] = R_GetTexture(lightcubemap);
2125 m.pointer_texcoord3f[1] = vertex3f;
2126 m.texmatrix[1] = *matrix_modeltolight;
2128 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2129 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2132 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2134 // this final code is shared
2136 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2137 VectorScale(lightcolor, colorscale, color2);
2138 GL_LockArrays(0, numverts);
2139 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2141 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2142 R_Mesh_Draw(numverts, numtriangles, elements);
2144 c_rt_lighttris += numtriangles;
2146 GL_LockArrays(0, 0);
2148 if (specularscale && glosstexture != r_shadow_blankblacktexture)
2150 // FIXME: detect blendsquare!
2151 //if (gl_support_blendsquare)
2153 colorscale = specularscale;
2155 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2157 // 2/0/0/1/2 3D combine blendsquare path
2158 memset(&m, 0, sizeof(m));
2159 m.pointer_vertex = vertex3f;
2160 m.tex[0] = R_GetTexture(bumptexture);
2161 m.pointer_texcoord[0] = texcoord2f;
2162 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2163 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2164 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2165 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2167 GL_ColorMask(0,0,0,1);
2168 // this squares the result
2169 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2170 GL_LockArrays(0, numverts);
2171 R_Mesh_Draw(numverts, numtriangles, elements);
2172 GL_LockArrays(0, 0);
2174 c_rt_lighttris += numtriangles;
2176 memset(&m, 0, sizeof(m));
2177 m.pointer_vertex = vertex3f;
2179 GL_LockArrays(0, numverts);
2180 // square alpha in framebuffer a few times to make it shiny
2181 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2182 // these comments are a test run through this math for intensity 0.5
2183 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2184 // 0.25 * 0.25 = 0.0625 (this is another pass)
2185 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2186 R_Mesh_Draw(numverts, numtriangles, elements);
2188 c_rt_lighttris += numtriangles;
2189 R_Mesh_Draw(numverts, numtriangles, elements);
2191 c_rt_lighttris += numtriangles;
2192 GL_LockArrays(0, 0);
2194 memset(&m, 0, sizeof(m));
2195 m.pointer_vertex = vertex3f;
2196 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2198 m.pointer_texcoord3f[0] = vertex3f;
2199 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2201 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2202 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2205 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2206 GL_LockArrays(0, numverts);
2207 R_Mesh_Draw(numverts, numtriangles, elements);
2208 GL_LockArrays(0, 0);
2210 c_rt_lighttris += numtriangles;
2212 memset(&m, 0, sizeof(m));
2213 m.pointer_vertex = vertex3f;
2214 m.tex[0] = R_GetTexture(glosstexture);
2215 m.pointer_texcoord[0] = texcoord2f;
2218 m.texcubemap[1] = R_GetTexture(lightcubemap);
2220 m.pointer_texcoord3f[1] = vertex3f;
2221 m.texmatrix[1] = *matrix_modeltolight;
2223 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2224 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2227 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2229 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2231 // 2/0/0/2 3D combine blendsquare path
2232 memset(&m, 0, sizeof(m));
2233 m.pointer_vertex = vertex3f;
2234 m.tex[0] = R_GetTexture(bumptexture);
2235 m.pointer_texcoord[0] = texcoord2f;
2236 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2237 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2238 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2239 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2241 GL_ColorMask(0,0,0,1);
2242 // this squares the result
2243 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2244 GL_LockArrays(0, numverts);
2245 R_Mesh_Draw(numverts, numtriangles, elements);
2246 GL_LockArrays(0, 0);
2248 c_rt_lighttris += numtriangles;
2250 memset(&m, 0, sizeof(m));
2251 m.pointer_vertex = vertex3f;
2253 GL_LockArrays(0, numverts);
2254 // square alpha in framebuffer a few times to make it shiny
2255 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2256 // these comments are a test run through this math for intensity 0.5
2257 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2258 // 0.25 * 0.25 = 0.0625 (this is another pass)
2259 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2260 R_Mesh_Draw(numverts, numtriangles, elements);
2262 c_rt_lighttris += numtriangles;
2263 R_Mesh_Draw(numverts, numtriangles, elements);
2265 c_rt_lighttris += numtriangles;
2266 GL_LockArrays(0, 0);
2268 memset(&m, 0, sizeof(m));
2269 m.pointer_vertex = vertex3f;
2270 m.tex[0] = R_GetTexture(glosstexture);
2271 m.pointer_texcoord[0] = texcoord2f;
2272 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2274 m.pointer_texcoord3f[1] = vertex3f;
2275 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2277 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2278 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2280 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2284 // 2/0/0/2/2 2D combine blendsquare path
2285 memset(&m, 0, sizeof(m));
2286 m.pointer_vertex = vertex3f;
2287 m.tex[0] = R_GetTexture(bumptexture);
2288 m.pointer_texcoord[0] = texcoord2f;
2289 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2290 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2291 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2292 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2294 GL_ColorMask(0,0,0,1);
2295 // this squares the result
2296 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2297 GL_LockArrays(0, numverts);
2298 R_Mesh_Draw(numverts, numtriangles, elements);
2299 GL_LockArrays(0, 0);
2301 c_rt_lighttris += numtriangles;
2303 memset(&m, 0, sizeof(m));
2304 m.pointer_vertex = vertex3f;
2306 GL_LockArrays(0, numverts);
2307 // square alpha in framebuffer a few times to make it shiny
2308 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2309 // these comments are a test run through this math for intensity 0.5
2310 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2311 // 0.25 * 0.25 = 0.0625 (this is another pass)
2312 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2313 R_Mesh_Draw(numverts, numtriangles, elements);
2315 c_rt_lighttris += numtriangles;
2316 R_Mesh_Draw(numverts, numtriangles, elements);
2318 c_rt_lighttris += numtriangles;
2319 GL_LockArrays(0, 0);
2321 memset(&m, 0, sizeof(m));
2322 m.pointer_vertex = vertex3f;
2323 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2325 m.pointer_texcoord3f[0] = vertex3f;
2326 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2328 m.pointer_texcoord[0] = varray_texcoord2f[0];
2329 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2331 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2333 m.pointer_texcoord3f[1] = vertex3f;
2334 m.texmatrix[1] = *matrix_modeltoattenuationz;
2336 m.pointer_texcoord[1] = varray_texcoord2f[1];
2337 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2340 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2341 GL_LockArrays(0, numverts);
2342 R_Mesh_Draw(numverts, numtriangles, elements);
2343 GL_LockArrays(0, 0);
2345 c_rt_lighttris += numtriangles;
2347 memset(&m, 0, sizeof(m));
2348 m.pointer_vertex = vertex3f;
2349 m.tex[0] = R_GetTexture(glosstexture);
2350 m.pointer_texcoord[0] = texcoord2f;
2353 m.texcubemap[1] = R_GetTexture(lightcubemap);
2355 m.pointer_texcoord3f[1] = vertex3f;
2356 m.texmatrix[1] = *matrix_modeltolight;
2358 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2359 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2362 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2365 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2366 VectorScale(lightcolor, colorscale, color2);
2367 GL_LockArrays(0, numverts);
2368 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2370 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2371 R_Mesh_Draw(numverts, numtriangles, elements);
2373 c_rt_lighttris += numtriangles;
2375 GL_LockArrays(0, 0);
2383 GL_BlendFunc(GL_ONE, GL_ONE);
2384 VectorScale(lightcolor, ambientscale, color2);
2385 memset(&m, 0, sizeof(m));
2386 m.pointer_vertex = vertex3f;
2387 m.tex[0] = R_GetTexture(basetexture);
2388 m.pointer_texcoord[0] = texcoord2f;
2389 if (r_textureunits.integer >= 2)
2392 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2394 m.pointer_texcoord3f[1] = vertex3f;
2395 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2397 m.pointer_texcoord[1] = varray_texcoord2f[1];
2398 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2400 if (r_textureunits.integer >= 3)
2402 // Geforce3/Radeon class but not using dot3
2403 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2405 m.pointer_texcoord3f[2] = vertex3f;
2406 m.texmatrix[2] = *matrix_modeltoattenuationz;
2408 m.pointer_texcoord[2] = varray_texcoord2f[2];
2409 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2413 if (r_textureunits.integer >= 3)
2414 m.pointer_color = NULL;
2416 m.pointer_color = varray_color4f;
2418 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2420 color[0] = bound(0, color2[0], 1);
2421 color[1] = bound(0, color2[1], 1);
2422 color[2] = bound(0, color2[2], 1);
2423 if (r_textureunits.integer >= 3)
2424 GL_Color(color[0], color[1], color[2], 1);
2425 else if (r_textureunits.integer >= 2)
2426 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2428 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2429 GL_LockArrays(0, numverts);
2430 R_Mesh_Draw(numverts, numtriangles, elements);
2431 GL_LockArrays(0, 0);
2433 c_rt_lighttris += numtriangles;
2438 GL_BlendFunc(GL_ONE, GL_ONE);
2439 VectorScale(lightcolor, diffusescale, color2);
2440 memset(&m, 0, sizeof(m));
2441 m.pointer_vertex = vertex3f;
2442 m.pointer_color = varray_color4f;
2443 m.tex[0] = R_GetTexture(basetexture);
2444 m.pointer_texcoord[0] = texcoord2f;
2445 if (r_textureunits.integer >= 2)
2448 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2450 m.pointer_texcoord3f[1] = vertex3f;
2451 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2453 m.pointer_texcoord[1] = varray_texcoord2f[1];
2454 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2456 if (r_textureunits.integer >= 3)
2458 // Geforce3/Radeon class but not using dot3
2459 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2461 m.pointer_texcoord3f[2] = vertex3f;
2462 m.texmatrix[2] = *matrix_modeltoattenuationz;
2464 m.pointer_texcoord[2] = varray_texcoord2f[2];
2465 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2470 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2472 color[0] = bound(0, color2[0], 1);
2473 color[1] = bound(0, color2[1], 1);
2474 color[2] = bound(0, color2[2], 1);
2475 if (r_textureunits.integer >= 3)
2476 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2477 else if (r_textureunits.integer >= 2)
2478 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2480 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2481 GL_LockArrays(0, numverts);
2482 R_Mesh_Draw(numverts, numtriangles, elements);
2483 GL_LockArrays(0, 0);
2485 c_rt_lighttris += numtriangles;
2491 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2495 R_RTLight_Uncompile(rtlight);
2496 memset(rtlight, 0, sizeof(*rtlight));
2498 VectorCopy(light->origin, rtlight->shadoworigin);
2499 VectorCopy(light->color, rtlight->color);
2500 rtlight->radius = light->radius;
2501 //rtlight->cullradius = rtlight->radius;
2502 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2503 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2504 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2505 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2506 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2507 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2508 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2509 rtlight->cubemapname[0] = 0;
2510 if (light->cubemapname[0])
2511 strcpy(rtlight->cubemapname, light->cubemapname);
2512 else if (light->cubemapnum > 0)
2513 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2514 rtlight->shadow = light->shadow;
2515 rtlight->corona = light->corona;
2516 rtlight->style = light->style;
2517 rtlight->isstatic = isstatic;
2518 rtlight->coronasizescale = light->coronasizescale;
2519 rtlight->ambientscale = light->ambientscale;
2520 rtlight->diffusescale = light->diffusescale;
2521 rtlight->specularscale = light->specularscale;
2522 rtlight->flags = light->flags;
2523 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2524 // ConcatScale won't work here because this needs to scale rotate and
2525 // translate, not just rotate
2526 scale = 1.0f / rtlight->radius;
2527 for (k = 0;k < 3;k++)
2528 for (j = 0;j < 4;j++)
2529 rtlight->matrix_worldtolight.m[k][j] *= scale;
2530 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2531 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2533 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2534 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2535 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2536 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2539 // compiles rtlight geometry
2540 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2541 void R_RTLight_Compile(rtlight_t *rtlight)
2543 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2544 entity_render_t *ent = r_refdef.worldentity;
2545 model_t *model = r_refdef.worldmodel;
2547 // compile the light
2548 rtlight->compiled = true;
2549 rtlight->static_numclusters = 0;
2550 rtlight->static_numclusterpvsbytes = 0;
2551 rtlight->static_clusterlist = NULL;
2552 rtlight->static_clusterpvs = NULL;
2553 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2554 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2555 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2556 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2557 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2558 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2560 if (model && model->GetLightInfo)
2562 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2563 r_shadow_compilingrtlight = rtlight;
2564 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2565 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2566 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);
2567 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2568 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2571 rtlight->static_numclusters = numclusters;
2572 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2573 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2574 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2576 if (model->DrawShadowVolume && rtlight->shadow)
2578 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2579 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2580 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2582 if (model->DrawLight)
2584 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2585 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);
2586 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2588 // switch back to rendering when DrawShadowVolume or DrawLight is called
2589 r_shadow_compilingrtlight = NULL;
2593 // use smallest available cullradius - box radius or light radius
2594 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2595 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2599 if (rtlight->static_meshchain_shadow)
2602 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2605 shadowtris += mesh->numtriangles;
2611 if (rtlight->static_meshchain_light)
2614 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2617 lighttris += mesh->numtriangles;
2621 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);
2624 void R_RTLight_Uncompile(rtlight_t *rtlight)
2626 if (rtlight->compiled)
2628 if (rtlight->static_meshchain_shadow)
2629 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2630 rtlight->static_meshchain_shadow = NULL;
2631 if (rtlight->static_meshchain_light)
2632 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2633 rtlight->static_meshchain_light = NULL;
2634 if (rtlight->static_clusterlist)
2635 Mem_Free(rtlight->static_clusterlist);
2636 rtlight->static_clusterlist = NULL;
2637 if (rtlight->static_clusterpvs)
2638 Mem_Free(rtlight->static_clusterpvs);
2639 rtlight->static_clusterpvs = NULL;
2640 rtlight->static_numclusters = 0;
2641 rtlight->static_numclusterpvsbytes = 0;
2642 rtlight->compiled = false;
2646 void R_Shadow_UncompileWorldLights(void)
2649 for (light = r_shadow_worldlightchain;light;light = light->next)
2650 R_RTLight_Uncompile(&light->rtlight);
2653 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2655 int i, shadow, usestencil;
2656 entity_render_t *ent;
2658 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2659 rtexture_t *cubemaptexture;
2660 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2661 int numclusters, numsurfaces;
2662 int *clusterlist, *surfacelist;
2664 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2668 // skip lights that don't light (corona only lights)
2669 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2672 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2673 VectorScale(rtlight->color, f, lightcolor);
2674 if (VectorLength2(lightcolor) < 0.01)
2677 if (rtlight->selected)
2679 f = 2 + sin(realtime * M_PI * 4.0);
2680 VectorScale(lightcolor, f, lightcolor);
2684 // loading is done before visibility checks because loading should happen
2685 // all at once at the start of a level, not when it stalls gameplay.
2686 // (especially important to benchmarks)
2687 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2688 R_RTLight_Compile(rtlight);
2689 if (rtlight->cubemapname[0])
2690 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2692 cubemaptexture = NULL;
2694 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2695 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2696 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2697 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2698 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2699 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2700 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2707 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2709 // compiled light, world available and can receive realtime lighting
2710 // retrieve cluster information
2711 numclusters = rtlight->static_numclusters;
2712 clusterlist = rtlight->static_clusterlist;
2713 clusterpvs = rtlight->static_clusterpvs;
2714 VectorCopy(rtlight->cullmins, cullmins);
2715 VectorCopy(rtlight->cullmaxs, cullmaxs);
2717 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2719 // dynamic light, world available and can receive realtime lighting
2720 // if the light box is offscreen, skip it right away
2721 if (R_CullBox(cullmins, cullmaxs))
2723 // calculate lit surfaces and clusters
2724 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2725 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2726 r_refdef.worldmodel->GetLightInfo(&cl_entities[0].render, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2727 clusterlist = r_shadow_buffer_clusterlist;
2728 clusterpvs = r_shadow_buffer_clusterpvs;
2729 surfacelist = r_shadow_buffer_surfacelist;
2731 // if the reduced cluster bounds are offscreen, skip it
2732 if (R_CullBox(cullmins, cullmaxs))
2734 // check if light is illuminating any visible clusters
2737 for (i = 0;i < numclusters;i++)
2738 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2740 if (i == numclusters)
2743 // set up a scissor rectangle for this light
2744 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2747 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2750 if (shadow && (gl_stencil || visiblevolumes))
2752 if (!visiblevolumes)
2754 R_Shadow_Stage_ShadowVolumes();
2757 ent = &cl_entities[0].render;
2758 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2760 memset(&m, 0, sizeof(m));
2761 R_Mesh_Matrix(&ent->matrix);
2762 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2764 m.pointer_vertex = mesh->vertex3f;
2766 GL_LockArrays(0, mesh->numverts);
2767 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2769 // increment stencil if backface is behind depthbuffer
2770 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2771 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2772 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2773 c_rtcached_shadowmeshes++;
2774 c_rtcached_shadowtris += mesh->numtriangles;
2775 // decrement stencil if frontface is behind depthbuffer
2776 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2777 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2779 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2780 c_rtcached_shadowmeshes++;
2781 c_rtcached_shadowtris += mesh->numtriangles;
2782 GL_LockArrays(0, 0);
2785 else if (numsurfaces)
2787 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2788 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2790 if (r_drawentities.integer)
2792 for (i = 0;i < r_refdef.numentities;i++)
2794 ent = r_refdef.entities[i];
2796 if (r_shadow_cull.integer)
2798 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2800 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2803 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2805 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2806 // light emitting entities should not cast their own shadow
2807 if (VectorLength2(relativelightorigin) < 0.1)
2809 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2810 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2811 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2812 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2813 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2814 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2815 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2820 if (!visiblevolumes)
2822 R_Shadow_Stage_Light(usestencil);
2824 ent = &cl_entities[0].render;
2825 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2827 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2828 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2829 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2830 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2831 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2832 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2833 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2834 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2835 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2837 R_Mesh_Matrix(&ent->matrix);
2838 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2839 R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
2842 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2844 if (r_drawentities.integer)
2846 for (i = 0;i < r_refdef.numentities;i++)
2848 ent = r_refdef.entities[i];
2849 // can't draw transparent entity lighting here because
2850 // transparent meshes are deferred for later
2851 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)
2853 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2854 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2855 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2856 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2857 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2858 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2859 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2860 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2861 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);
2868 void R_ShadowVolumeLighting(int visiblevolumes)
2874 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2875 R_Shadow_EditLights_Reload_f();
2879 memset(&m, 0, sizeof(m));
2882 GL_BlendFunc(GL_ONE, GL_ONE);
2883 GL_DepthMask(false);
2884 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2885 qglDisable(GL_CULL_FACE);
2886 GL_Color(0.0, 0.0125, 0.1, 1);
2889 R_Shadow_Stage_Begin();
2890 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2891 if (r_shadow_debuglight.integer >= 0)
2893 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2894 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2895 R_DrawRTLight(&light->rtlight, visiblevolumes);
2898 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2899 if (light->flags & flag)
2900 R_DrawRTLight(&light->rtlight, visiblevolumes);
2902 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2903 R_DrawRTLight(&light->rtlight, visiblevolumes);
2907 qglEnable(GL_CULL_FACE);
2908 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2911 R_Shadow_Stage_End();
2914 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2915 typedef struct suffixinfo_s
2918 qboolean flipx, flipy, flipdiagonal;
2921 static suffixinfo_t suffix[3][6] =
2924 {"px", false, false, false},
2925 {"nx", false, false, false},
2926 {"py", false, false, false},
2927 {"ny", false, false, false},
2928 {"pz", false, false, false},
2929 {"nz", false, false, false}
2932 {"posx", false, false, false},
2933 {"negx", false, false, false},
2934 {"posy", false, false, false},
2935 {"negy", false, false, false},
2936 {"posz", false, false, false},
2937 {"negz", false, false, false}
2940 {"rt", true, false, true},
2941 {"lf", false, true, true},
2942 {"ft", true, true, false},
2943 {"bk", false, false, false},
2944 {"up", true, false, true},
2945 {"dn", true, false, true}
2949 static int componentorder[4] = {0, 1, 2, 3};
2951 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2953 int i, j, cubemapsize;
2954 qbyte *cubemappixels, *image_rgba;
2955 rtexture_t *cubemaptexture;
2957 // must start 0 so the first loadimagepixels has no requested width/height
2959 cubemappixels = NULL;
2960 cubemaptexture = NULL;
2961 // keep trying different suffix groups (posx, px, rt) until one loads
2962 for (j = 0;j < 3 && !cubemappixels;j++)
2964 // load the 6 images in the suffix group
2965 for (i = 0;i < 6;i++)
2967 // generate an image name based on the base and and suffix
2968 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2970 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2972 // an image loaded, make sure width and height are equal
2973 if (image_width == image_height)
2975 // if this is the first image to load successfully, allocate the cubemap memory
2976 if (!cubemappixels && image_width >= 1)
2978 cubemapsize = image_width;
2979 // note this clears to black, so unavailable sides are black
2980 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2982 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2984 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);
2987 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2989 Mem_Free(image_rgba);
2993 // if a cubemap loaded, upload it
2996 if (!r_shadow_filters_texturepool)
2997 r_shadow_filters_texturepool = R_AllocTexturePool();
2998 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2999 Mem_Free(cubemappixels);
3003 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3004 for (j = 0;j < 3;j++)
3005 for (i = 0;i < 6;i++)
3006 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3007 Con_Print(" and was unable to find any of them.\n");
3009 return cubemaptexture;
3012 rtexture_t *R_Shadow_Cubemap(const char *basename)
3015 for (i = 0;i < numcubemaps;i++)
3016 if (!strcasecmp(cubemaps[i].basename, basename))
3017 return cubemaps[i].texture;
3018 if (i >= MAX_CUBEMAPS)
3021 strcpy(cubemaps[i].basename, basename);
3022 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3023 return cubemaps[i].texture;
3026 void R_Shadow_FreeCubemaps(void)
3029 R_FreeTexturePool(&r_shadow_filters_texturepool);
3032 dlight_t *R_Shadow_NewWorldLight(void)
3035 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3036 light->next = r_shadow_worldlightchain;
3037 r_shadow_worldlightchain = light;
3041 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)
3043 VectorCopy(origin, light->origin);
3044 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3045 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3046 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3047 light->color[0] = max(color[0], 0);
3048 light->color[1] = max(color[1], 0);
3049 light->color[2] = max(color[2], 0);
3050 light->radius = max(radius, 0);
3051 light->style = style;
3052 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3054 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3057 light->shadow = shadowenable;
3058 light->corona = corona;
3061 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3062 light->coronasizescale = coronasizescale;
3063 light->ambientscale = ambientscale;
3064 light->diffusescale = diffusescale;
3065 light->specularscale = specularscale;
3066 light->flags = flags;
3067 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3069 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3072 void R_Shadow_FreeWorldLight(dlight_t *light)
3074 dlight_t **lightpointer;
3075 R_RTLight_Uncompile(&light->rtlight);
3076 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3077 if (*lightpointer != light)
3078 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3079 *lightpointer = light->next;
3083 void R_Shadow_ClearWorldLights(void)
3085 while (r_shadow_worldlightchain)
3086 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3087 r_shadow_selectedlight = NULL;
3088 R_Shadow_FreeCubemaps();
3091 void R_Shadow_SelectLight(dlight_t *light)
3093 if (r_shadow_selectedlight)
3094 r_shadow_selectedlight->selected = false;
3095 r_shadow_selectedlight = light;
3096 if (r_shadow_selectedlight)
3097 r_shadow_selectedlight->selected = true;
3100 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3102 float scale = r_editlights_cursorgrid.value * 0.5f;
3103 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);
3106 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3109 const dlight_t *light;
3112 if (light->selected)
3113 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3116 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);
3119 void R_Shadow_DrawLightSprites(void)
3125 for (i = 0;i < 5;i++)
3127 lighttextures[i] = NULL;
3128 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3129 lighttextures[i] = pic->tex;
3132 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3133 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3134 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3137 void R_Shadow_SelectLightInView(void)
3139 float bestrating, rating, temp[3];
3140 dlight_t *best, *light;
3143 for (light = r_shadow_worldlightchain;light;light = light->next)
3145 VectorSubtract(light->origin, r_vieworigin, temp);
3146 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3149 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3150 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3152 bestrating = rating;
3157 R_Shadow_SelectLight(best);
3160 void R_Shadow_LoadWorldLights(void)
3162 int n, a, style, shadow, flags;
3163 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3164 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3165 if (r_refdef.worldmodel == NULL)
3167 Con_Print("No map loaded.\n");
3170 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3171 strlcat (name, ".rtlights", sizeof (name));
3172 lightsstring = FS_LoadFile(name, tempmempool, false);
3182 for (;COM_Parse(t, true) && strcmp(
3183 if (COM_Parse(t, true))
3185 if (com_token[0] == '!')
3188 origin[0] = atof(com_token+1);
3191 origin[0] = atof(com_token);
3196 while (*s && *s != '\n' && *s != '\r')
3202 // check for modifier flags
3209 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);
3212 flags = LIGHTFLAG_REALTIMEMODE;
3220 coronasizescale = 0.25f;
3222 VectorClear(angles);
3225 if (a < 9 || !strcmp(cubemapname, "\"\""))
3227 // remove quotes on cubemapname
3228 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3230 cubemapname[strlen(cubemapname)-1] = 0;
3231 strcpy(cubemapname, cubemapname + 1);
3235 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);
3238 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3239 radius *= r_editlights_rtlightssizescale.value;
3240 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3248 Con_Printf("invalid rtlights file \"%s\"\n", name);
3249 Mem_Free(lightsstring);
3253 void R_Shadow_SaveWorldLights(void)
3256 int bufchars, bufmaxchars;
3258 char name[MAX_QPATH];
3260 if (!r_shadow_worldlightchain)
3262 if (r_refdef.worldmodel == NULL)
3264 Con_Print("No map loaded.\n");
3267 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3268 strlcat (name, ".rtlights", sizeof (name));
3269 bufchars = bufmaxchars = 0;
3271 for (light = r_shadow_worldlightchain;light;light = light->next)
3273 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3274 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);
3275 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3276 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]);
3278 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);
3279 if (bufchars + (int) strlen(line) > bufmaxchars)
3281 bufmaxchars = bufchars + strlen(line) + 2048;
3283 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3287 memcpy(buf, oldbuf, bufchars);
3293 memcpy(buf + bufchars, line, strlen(line));
3294 bufchars += strlen(line);
3298 FS_WriteFile(name, buf, bufchars);
3303 void R_Shadow_LoadLightsFile(void)
3306 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3307 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3308 if (r_refdef.worldmodel == NULL)
3310 Con_Print("No map loaded.\n");
3313 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3314 strlcat (name, ".lights", sizeof (name));
3315 lightsstring = FS_LoadFile(name, tempmempool, false);
3323 while (*s && *s != '\n' && *s != '\r')
3329 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);
3333 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);
3336 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3337 radius = bound(15, radius, 4096);
3338 VectorScale(color, (2.0f / (8388608.0f)), color);
3339 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3347 Con_Printf("invalid lights file \"%s\"\n", name);
3348 Mem_Free(lightsstring);
3352 // tyrlite/hmap2 light types in the delay field
3353 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3355 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3357 int entnum, style, islight, skin, pflags, effects, type, n;
3360 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3361 char key[256], value[1024];
3363 if (r_refdef.worldmodel == NULL)
3365 Con_Print("No map loaded.\n");
3368 // try to load a .ent file first
3369 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3370 strlcat (key, ".ent", sizeof (key));
3371 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3372 // and if that is not found, fall back to the bsp file entity string
3374 data = r_refdef.worldmodel->brush.entities;
3377 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3379 type = LIGHTTYPE_MINUSX;
3380 origin[0] = origin[1] = origin[2] = 0;
3381 originhack[0] = originhack[1] = originhack[2] = 0;
3382 angles[0] = angles[1] = angles[2] = 0;
3383 color[0] = color[1] = color[2] = 1;
3384 light[0] = light[1] = light[2] = 1;light[3] = 300;
3385 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3395 if (!COM_ParseToken(&data, false))
3397 if (com_token[0] == '}')
3398 break; // end of entity
3399 if (com_token[0] == '_')
3400 strcpy(key, com_token + 1);
3402 strcpy(key, com_token);
3403 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3404 key[strlen(key)-1] = 0;
3405 if (!COM_ParseToken(&data, false))
3407 strcpy(value, com_token);
3409 // now that we have the key pair worked out...
3410 if (!strcmp("light", key))
3412 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3416 light[0] = vec[0] * (1.0f / 256.0f);
3417 light[1] = vec[0] * (1.0f / 256.0f);
3418 light[2] = vec[0] * (1.0f / 256.0f);
3424 light[0] = vec[0] * (1.0f / 255.0f);
3425 light[1] = vec[1] * (1.0f / 255.0f);
3426 light[2] = vec[2] * (1.0f / 255.0f);
3430 else if (!strcmp("delay", key))
3432 else if (!strcmp("origin", key))
3433 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3434 else if (!strcmp("angle", key))
3435 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3436 else if (!strcmp("angles", key))
3437 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3438 else if (!strcmp("color", key))
3439 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3440 else if (!strcmp("wait", key))
3441 fadescale = atof(value);
3442 else if (!strcmp("classname", key))
3444 if (!strncmp(value, "light", 5))
3447 if (!strcmp(value, "light_fluoro"))
3452 overridecolor[0] = 1;
3453 overridecolor[1] = 1;
3454 overridecolor[2] = 1;
3456 if (!strcmp(value, "light_fluorospark"))
3461 overridecolor[0] = 1;
3462 overridecolor[1] = 1;
3463 overridecolor[2] = 1;
3465 if (!strcmp(value, "light_globe"))
3470 overridecolor[0] = 1;
3471 overridecolor[1] = 0.8;
3472 overridecolor[2] = 0.4;
3474 if (!strcmp(value, "light_flame_large_yellow"))
3479 overridecolor[0] = 1;
3480 overridecolor[1] = 0.5;
3481 overridecolor[2] = 0.1;
3483 if (!strcmp(value, "light_flame_small_yellow"))
3488 overridecolor[0] = 1;
3489 overridecolor[1] = 0.5;
3490 overridecolor[2] = 0.1;
3492 if (!strcmp(value, "light_torch_small_white"))
3497 overridecolor[0] = 1;
3498 overridecolor[1] = 0.5;
3499 overridecolor[2] = 0.1;
3501 if (!strcmp(value, "light_torch_small_walltorch"))
3506 overridecolor[0] = 1;
3507 overridecolor[1] = 0.5;
3508 overridecolor[2] = 0.1;
3512 else if (!strcmp("style", key))
3513 style = atoi(value);
3514 else if (r_refdef.worldmodel->type == mod_brushq3)
3516 if (!strcmp("scale", key))
3517 lightscale = atof(value);
3518 if (!strcmp("fade", key))
3519 fadescale = atof(value);
3521 else if (!strcmp("skin", key))
3522 skin = (int)atof(value);
3523 else if (!strcmp("pflags", key))
3524 pflags = (int)atof(value);
3525 else if (!strcmp("effects", key))
3526 effects = (int)atof(value);
3530 if (lightscale <= 0)
3534 if (color[0] == color[1] && color[0] == color[2])
3536 color[0] *= overridecolor[0];
3537 color[1] *= overridecolor[1];
3538 color[2] *= overridecolor[2];
3540 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3541 color[0] = color[0] * light[0];
3542 color[1] = color[1] * light[1];
3543 color[2] = color[2] * light[2];
3546 case LIGHTTYPE_MINUSX:
3548 case LIGHTTYPE_RECIPX:
3550 VectorScale(color, (1.0f / 16.0f), color);
3552 case LIGHTTYPE_RECIPXX:
3554 VectorScale(color, (1.0f / 16.0f), color);
3557 case LIGHTTYPE_NONE:
3561 case LIGHTTYPE_MINUSXX:
3564 VectorAdd(origin, originhack, origin);
3566 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);
3569 Mem_Free(entfiledata);
3573 void R_Shadow_SetCursorLocationForView(void)
3575 vec_t dist, push, frac;
3576 vec3_t dest, endpos, normal;
3577 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3578 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3581 dist = frac * r_editlights_cursordistance.value;
3582 push = r_editlights_cursorpushback.value;
3586 VectorMA(endpos, push, r_viewforward, endpos);
3587 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3589 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3590 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3591 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3594 void R_Shadow_UpdateWorldLightSelection(void)
3596 if (r_editlights.integer)
3598 R_Shadow_SetCursorLocationForView();
3599 R_Shadow_SelectLightInView();
3600 R_Shadow_DrawLightSprites();
3603 R_Shadow_SelectLight(NULL);
3606 void R_Shadow_EditLights_Clear_f(void)
3608 R_Shadow_ClearWorldLights();
3611 void R_Shadow_EditLights_Reload_f(void)
3613 if (!r_refdef.worldmodel)
3615 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3616 R_Shadow_ClearWorldLights();
3617 R_Shadow_LoadWorldLights();
3618 if (r_shadow_worldlightchain == NULL)
3620 R_Shadow_LoadLightsFile();
3621 if (r_shadow_worldlightchain == NULL)
3622 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3626 void R_Shadow_EditLights_Save_f(void)
3628 if (!r_refdef.worldmodel)
3630 R_Shadow_SaveWorldLights();
3633 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3635 R_Shadow_ClearWorldLights();
3636 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3639 void R_Shadow_EditLights_ImportLightsFile_f(void)
3641 R_Shadow_ClearWorldLights();
3642 R_Shadow_LoadLightsFile();
3645 void R_Shadow_EditLights_Spawn_f(void)
3648 if (!r_editlights.integer)
3650 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3653 if (Cmd_Argc() != 1)
3655 Con_Print("r_editlights_spawn does not take parameters\n");
3658 color[0] = color[1] = color[2] = 1;
3659 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3662 void R_Shadow_EditLights_Edit_f(void)
3664 vec3_t origin, angles, color;
3665 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3666 int style, shadows, flags, normalmode, realtimemode;
3667 char cubemapname[1024];
3668 if (!r_editlights.integer)
3670 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3673 if (!r_shadow_selectedlight)
3675 Con_Print("No selected light.\n");
3678 VectorCopy(r_shadow_selectedlight->origin, origin);
3679 VectorCopy(r_shadow_selectedlight->angles, angles);
3680 VectorCopy(r_shadow_selectedlight->color, color);
3681 radius = r_shadow_selectedlight->radius;
3682 style = r_shadow_selectedlight->style;
3683 if (r_shadow_selectedlight->cubemapname)
3684 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3687 shadows = r_shadow_selectedlight->shadow;
3688 corona = r_shadow_selectedlight->corona;
3689 coronasizescale = r_shadow_selectedlight->coronasizescale;
3690 ambientscale = r_shadow_selectedlight->ambientscale;
3691 diffusescale = r_shadow_selectedlight->diffusescale;
3692 specularscale = r_shadow_selectedlight->specularscale;
3693 flags = r_shadow_selectedlight->flags;
3694 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3695 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3696 if (!strcmp(Cmd_Argv(1), "origin"))
3698 if (Cmd_Argc() != 5)
3700 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3703 origin[0] = atof(Cmd_Argv(2));
3704 origin[1] = atof(Cmd_Argv(3));
3705 origin[2] = atof(Cmd_Argv(4));
3707 else if (!strcmp(Cmd_Argv(1), "originx"))
3709 if (Cmd_Argc() != 3)
3711 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3714 origin[0] = atof(Cmd_Argv(2));
3716 else if (!strcmp(Cmd_Argv(1), "originy"))
3718 if (Cmd_Argc() != 3)
3720 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3723 origin[1] = atof(Cmd_Argv(2));
3725 else if (!strcmp(Cmd_Argv(1), "originz"))
3727 if (Cmd_Argc() != 3)
3729 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3732 origin[2] = atof(Cmd_Argv(2));
3734 else if (!strcmp(Cmd_Argv(1), "move"))
3736 if (Cmd_Argc() != 5)
3738 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3741 origin[0] += atof(Cmd_Argv(2));
3742 origin[1] += atof(Cmd_Argv(3));
3743 origin[2] += atof(Cmd_Argv(4));
3745 else if (!strcmp(Cmd_Argv(1), "movex"))
3747 if (Cmd_Argc() != 3)
3749 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3752 origin[0] += atof(Cmd_Argv(2));
3754 else if (!strcmp(Cmd_Argv(1), "movey"))
3756 if (Cmd_Argc() != 3)
3758 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3761 origin[1] += atof(Cmd_Argv(2));
3763 else if (!strcmp(Cmd_Argv(1), "movez"))
3765 if (Cmd_Argc() != 3)
3767 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3770 origin[2] += atof(Cmd_Argv(2));
3772 else if (!strcmp(Cmd_Argv(1), "angles"))
3774 if (Cmd_Argc() != 5)
3776 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3779 angles[0] = atof(Cmd_Argv(2));
3780 angles[1] = atof(Cmd_Argv(3));
3781 angles[2] = atof(Cmd_Argv(4));
3783 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3785 if (Cmd_Argc() != 3)
3787 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3790 angles[0] = atof(Cmd_Argv(2));
3792 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3794 if (Cmd_Argc() != 3)
3796 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3799 angles[1] = atof(Cmd_Argv(2));
3801 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3803 if (Cmd_Argc() != 3)
3805 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3808 angles[2] = atof(Cmd_Argv(2));
3810 else if (!strcmp(Cmd_Argv(1), "color"))
3812 if (Cmd_Argc() != 5)
3814 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3817 color[0] = atof(Cmd_Argv(2));
3818 color[1] = atof(Cmd_Argv(3));
3819 color[2] = atof(Cmd_Argv(4));
3821 else if (!strcmp(Cmd_Argv(1), "radius"))
3823 if (Cmd_Argc() != 3)
3825 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3828 radius = atof(Cmd_Argv(2));
3830 else if (!strcmp(Cmd_Argv(1), "style"))
3832 if (Cmd_Argc() != 3)
3834 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3837 style = atoi(Cmd_Argv(2));
3839 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3843 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3846 if (Cmd_Argc() == 3)
3847 strcpy(cubemapname, Cmd_Argv(2));
3851 else if (!strcmp(Cmd_Argv(1), "shadows"))
3853 if (Cmd_Argc() != 3)
3855 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3858 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3860 else if (!strcmp(Cmd_Argv(1), "corona"))
3862 if (Cmd_Argc() != 3)
3864 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3867 corona = atof(Cmd_Argv(2));
3869 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3871 if (Cmd_Argc() != 3)
3873 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3876 coronasizescale = atof(Cmd_Argv(2));
3878 else if (!strcmp(Cmd_Argv(1), "ambient"))
3880 if (Cmd_Argc() != 3)
3882 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3885 ambientscale = atof(Cmd_Argv(2));
3887 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3889 if (Cmd_Argc() != 3)
3891 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3894 diffusescale = atof(Cmd_Argv(2));
3896 else if (!strcmp(Cmd_Argv(1), "specular"))
3898 if (Cmd_Argc() != 3)
3900 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3903 specularscale = atof(Cmd_Argv(2));
3905 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3907 if (Cmd_Argc() != 3)
3909 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3912 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3914 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3916 if (Cmd_Argc() != 3)
3918 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3921 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3925 Con_Print("usage: r_editlights_edit [property] [value]\n");
3926 Con_Print("Selected light's properties:\n");
3927 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3928 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3929 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3930 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3931 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3932 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3933 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3934 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3935 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3936 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3937 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3938 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3939 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3940 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3943 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3944 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3947 void R_Shadow_EditLights_EditAll_f(void)
3951 if (!r_editlights.integer)
3953 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3957 for (light = r_shadow_worldlightchain;light;light = light->next)
3959 R_Shadow_SelectLight(light);
3960 R_Shadow_EditLights_Edit_f();
3964 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3966 int lightnumber, lightcount;
3970 if (!r_editlights.integer)
3976 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3977 if (light == r_shadow_selectedlight)
3978 lightnumber = lightcount;
3979 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;
3980 if (r_shadow_selectedlight == NULL)
3982 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3983 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;
3984 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;
3985 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;
3986 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3987 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3988 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3989 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;
3990 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3991 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3992 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3993 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3994 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3995 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;
3996 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;
3999 void R_Shadow_EditLights_ToggleShadow_f(void)
4001 if (!r_editlights.integer)
4003 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4006 if (!r_shadow_selectedlight)
4008 Con_Print("No selected light.\n");
4011 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);
4014 void R_Shadow_EditLights_ToggleCorona_f(void)
4016 if (!r_editlights.integer)
4018 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4021 if (!r_shadow_selectedlight)
4023 Con_Print("No selected light.\n");
4026 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);
4029 void R_Shadow_EditLights_Remove_f(void)
4031 if (!r_editlights.integer)
4033 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4036 if (!r_shadow_selectedlight)
4038 Con_Print("No selected light.\n");
4041 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4042 r_shadow_selectedlight = NULL;
4045 void R_Shadow_EditLights_Help_f(void)
4048 "Documentation on r_editlights system:\n"
4050 "r_editlights : enable/disable editing mode\n"
4051 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4052 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4053 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4054 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4055 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4056 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4057 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4059 "r_editlights_help : this help\n"
4060 "r_editlights_clear : remove all lights\n"
4061 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4062 "r_editlights_save : save to .rtlights file\n"
4063 "r_editlights_spawn : create a light with default settings\n"
4064 "r_editlights_edit command : edit selected light - more documentation below\n"
4065 "r_editlights_remove : remove selected light\n"
4066 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4067 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4068 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4070 "origin x y z : set light location\n"
4071 "originx x: set x component of light location\n"
4072 "originy y: set y component of light location\n"
4073 "originz z: set z component of light location\n"
4074 "move x y z : adjust light location\n"
4075 "movex x: adjust x component of light location\n"
4076 "movey y: adjust y component of light location\n"
4077 "movez z: adjust z component of light location\n"
4078 "angles x y z : set light angles\n"
4079 "anglesx x: set x component of light angles\n"
4080 "anglesy y: set y component of light angles\n"
4081 "anglesz z: set z component of light angles\n"
4082 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4083 "radius radius : set radius (size) of light\n"
4084 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4085 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4086 "shadows 1/0 : turn on/off shadows\n"
4087 "corona n : set corona intensity\n"
4088 "coronasize n : set corona size (0-1)\n"
4089 "ambient n : set ambient intensity (0-1)\n"
4090 "diffuse n : set diffuse intensity (0-1)\n"
4091 "specular n : set specular intensity (0-1)\n"
4092 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4093 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4094 "<nothing> : print light properties to console\n"
4098 void R_Shadow_EditLights_CopyInfo_f(void)
4100 if (!r_editlights.integer)
4102 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4105 if (!r_shadow_selectedlight)
4107 Con_Print("No selected light.\n");
4110 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4111 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4112 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4113 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4114 if (r_shadow_selectedlight->cubemapname)
4115 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4117 r_shadow_bufferlight.cubemapname[0] = 0;
4118 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4119 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4120 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4121 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4122 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4123 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4124 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4127 void R_Shadow_EditLights_PasteInfo_f(void)
4129 if (!r_editlights.integer)
4131 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4134 if (!r_shadow_selectedlight)
4136 Con_Print("No selected light.\n");
4139 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);
4142 void R_Shadow_EditLights_Init(void)
4144 Cvar_RegisterVariable(&r_editlights);
4145 Cvar_RegisterVariable(&r_editlights_cursordistance);
4146 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4147 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4148 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4149 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4150 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4151 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4152 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4153 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4154 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4155 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4156 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4157 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4158 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4159 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4160 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4161 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4162 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4163 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4164 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4165 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);