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)
741 int i, j, tris = 0, vr[3], t, 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 t = shadowmarktris[i];
771 e = inelement3i + t * 3;
772 // make sure the vertices are created
773 for (j = 0;j < 3;j++)
775 if (vertexupdate[e[j]] != vertexupdatenum)
777 vertexupdate[e[j]] = vertexupdatenum;
778 vertexremap[e[j]] = outvertices;
779 v = invertex3f + e[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(v, projectorigin, temp);
783 f = projectdistance / VectorLength(temp);
784 VectorCopy(v, outvertex3f);
785 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
792 for (i = 0;i < numshadowmarktris;i++)
794 t = shadowmarktris[i];
795 e = inelement3i + t * 3;
796 n = inneighbor3i + t * 3;
797 // output the front and back triangles
798 outelement3i[0] = vertexremap[e[0]];
799 outelement3i[1] = vertexremap[e[1]];
800 outelement3i[2] = vertexremap[e[2]];
801 outelement3i[3] = vertexremap[e[2]] + 1;
802 outelement3i[4] = vertexremap[e[1]] + 1;
803 outelement3i[5] = vertexremap[e[0]] + 1;
806 // output the sides (facing outward from this triangle)
807 if (shadowmark[n[0]] != shadowmarkcount)
809 vr[0] = vertexremap[e[0]];
810 vr[1] = vertexremap[e[1]];
811 outelement3i[0] = vr[1];
812 outelement3i[1] = vr[0];
813 outelement3i[2] = vr[0] + 1;
814 outelement3i[3] = vr[1];
815 outelement3i[4] = vr[0] + 1;
816 outelement3i[5] = vr[1] + 1;
820 if (shadowmark[n[1]] != shadowmarkcount)
822 vr[1] = vertexremap[e[1]];
823 vr[2] = vertexremap[e[2]];
824 outelement3i[0] = vr[2];
825 outelement3i[1] = vr[1];
826 outelement3i[2] = vr[1] + 1;
827 outelement3i[3] = vr[2];
828 outelement3i[4] = vr[1] + 1;
829 outelement3i[5] = vr[2] + 1;
833 if (shadowmark[n[2]] != shadowmarkcount)
835 vr[0] = vertexremap[e[0]];
836 vr[2] = vertexremap[e[2]];
837 outelement3i[0] = vr[0];
838 outelement3i[1] = vr[2];
839 outelement3i[2] = vr[2] + 1;
840 outelement3i[3] = vr[0];
841 outelement3i[4] = vr[2] + 1;
842 outelement3i[5] = vr[0] + 1;
848 *outnumvertices = outvertices;
852 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)
855 if (projectdistance < 0.1)
857 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
860 if (!numverts || !nummarktris)
862 // make sure shadowelements is big enough for this volume
863 if (maxshadowelements < nummarktris * 24)
864 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
865 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
866 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
869 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)
874 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
876 tend = firsttriangle + numtris;
877 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
878 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
879 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
881 // surface box entirely inside light box, no box cull
882 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
883 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
884 shadowmarklist[numshadowmark++] = t;
888 // surface box not entirely inside light box, cull each triangle
889 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
891 v[0] = invertex3f + e[0] * 3;
892 v[1] = invertex3f + e[1] * 3;
893 v[2] = invertex3f + e[2] * 3;
894 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
895 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
896 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
897 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
898 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
899 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
900 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
901 shadowmarklist[numshadowmark++] = t;
906 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
909 if (r_shadow_compilingrtlight)
911 // if we're compiling an rtlight, capture the mesh
912 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
915 memset(&m, 0, sizeof(m));
916 m.pointer_vertex = vertex3f;
918 GL_LockArrays(0, numvertices);
919 if (r_shadowstage == SHADOWSTAGE_STENCIL)
921 // increment stencil if backface is behind depthbuffer
922 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
923 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
924 R_Mesh_Draw(numvertices, numtriangles, element3i);
926 c_rt_shadowtris += numtriangles;
927 // decrement stencil if frontface is behind depthbuffer
928 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
929 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
931 R_Mesh_Draw(numvertices, numtriangles, element3i);
933 c_rt_shadowtris += numtriangles;
937 static void R_Shadow_MakeTextures(void)
939 int x, y, z, d, side;
940 float v[3], s, t, intensity;
942 R_FreeTexturePool(&r_shadow_texturepool);
943 r_shadow_texturepool = R_AllocTexturePool();
944 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
945 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
947 #define ATTEN2DSIZE 64
948 #define ATTEN3DSIZE 32
949 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
950 data[0] = 128; // normal X
951 data[1] = 128; // normal Y
952 data[2] = 255; // normal Z
953 data[3] = 128; // height
954 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
959 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
964 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
969 r_shadow_blankblacktexture = R_LoadTexture2D(r_shadow_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
970 r_shadow_blankwhitecubetexture = NULL;
971 r_shadow_normalcubetexture = NULL;
972 if (gl_texturecubemap)
974 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
975 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
976 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
977 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
978 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
979 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
980 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
981 for (side = 0;side < 6;side++)
983 for (y = 0;y < NORMSIZE;y++)
985 for (x = 0;x < NORMSIZE;x++)
987 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
988 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1022 intensity = 127.0f / sqrt(DotProduct(v, v));
1023 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1024 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1025 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1026 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1030 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1032 for (y = 0;y < ATTEN2DSIZE;y++)
1034 for (x = 0;x < ATTEN2DSIZE;x++)
1036 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1037 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1039 intensity = 1.0f - sqrt(DotProduct(v, v));
1041 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1042 d = bound(0, intensity, 255);
1043 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1044 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1045 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1046 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1049 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1050 if (r_shadow_texture3d.integer)
1052 for (z = 0;z < ATTEN3DSIZE;z++)
1054 for (y = 0;y < ATTEN3DSIZE;y++)
1056 for (x = 0;x < ATTEN3DSIZE;x++)
1058 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1059 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1060 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1061 intensity = 1.0f - sqrt(DotProduct(v, v));
1063 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1064 d = bound(0, intensity, 255);
1065 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1066 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1067 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1068 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1072 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1077 void R_Shadow_ValidateCvars(void)
1079 if (r_shadow_texture3d.integer && !gl_texture3d)
1080 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1081 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1082 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1085 void R_Shadow_Stage_Begin(void)
1089 R_Shadow_ValidateCvars();
1091 if (!r_shadow_attenuation2dtexture
1092 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1093 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1094 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1095 R_Shadow_MakeTextures();
1097 memset(&m, 0, sizeof(m));
1098 GL_BlendFunc(GL_ONE, GL_ZERO);
1099 GL_DepthMask(false);
1102 GL_Color(0, 0, 0, 1);
1103 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1104 qglEnable(GL_CULL_FACE);
1105 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1106 r_shadowstage = SHADOWSTAGE_NONE;
1109 void R_Shadow_Stage_ShadowVolumes(void)
1112 memset(&m, 0, sizeof(m));
1114 GL_Color(1, 1, 1, 1);
1115 GL_ColorMask(0, 0, 0, 0);
1116 GL_BlendFunc(GL_ONE, GL_ZERO);
1117 GL_DepthMask(false);
1119 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1120 //if (r_shadow_shadow_polygonoffset.value != 0)
1122 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1123 // qglEnable(GL_POLYGON_OFFSET_FILL);
1126 // qglDisable(GL_POLYGON_OFFSET_FILL);
1127 qglDepthFunc(GL_LESS);
1128 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1129 qglEnable(GL_STENCIL_TEST);
1130 qglStencilFunc(GL_ALWAYS, 128, ~0);
1131 if (gl_ext_stenciltwoside.integer)
1133 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1134 qglDisable(GL_CULL_FACE);
1135 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1136 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1138 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1139 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1141 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1145 r_shadowstage = SHADOWSTAGE_STENCIL;
1146 qglEnable(GL_CULL_FACE);
1148 // this is changed by every shadow render so its value here is unimportant
1149 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1151 GL_Clear(GL_STENCIL_BUFFER_BIT);
1153 // LordHavoc note: many shadow volumes reside entirely inside the world
1154 // (that is to say they are entirely bounded by their lit surfaces),
1155 // which can be optimized by handling things as an inverted light volume,
1156 // with the shadow boundaries of the world being simulated by an altered
1157 // (129) bias to stencil clearing on such lights
1158 // FIXME: generate inverted light volumes for use as shadow volumes and
1159 // optimize for them as noted above
1162 void R_Shadow_Stage_Light(int shadowtest)
1165 memset(&m, 0, sizeof(m));
1167 GL_BlendFunc(GL_ONE, GL_ONE);
1168 GL_DepthMask(false);
1170 qglPolygonOffset(0, 0);
1171 //qglDisable(GL_POLYGON_OFFSET_FILL);
1172 GL_Color(1, 1, 1, 1);
1173 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1174 qglDepthFunc(GL_EQUAL);
1175 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1176 qglEnable(GL_CULL_FACE);
1178 qglEnable(GL_STENCIL_TEST);
1180 qglDisable(GL_STENCIL_TEST);
1181 if (gl_support_stenciltwoside)
1182 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1184 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1185 // only draw light where this geometry was already rendered AND the
1186 // stencil is 128 (values other than this mean shadow)
1187 qglStencilFunc(GL_EQUAL, 128, ~0);
1188 r_shadowstage = SHADOWSTAGE_LIGHT;
1192 void R_Shadow_Stage_End(void)
1195 memset(&m, 0, sizeof(m));
1197 GL_BlendFunc(GL_ONE, GL_ZERO);
1200 qglPolygonOffset(0, 0);
1201 //qglDisable(GL_POLYGON_OFFSET_FILL);
1202 GL_Color(1, 1, 1, 1);
1203 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1204 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1205 qglDepthFunc(GL_LEQUAL);
1206 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1207 qglDisable(GL_STENCIL_TEST);
1208 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1209 if (gl_support_stenciltwoside)
1210 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1212 qglStencilFunc(GL_ALWAYS, 128, ~0);
1213 r_shadowstage = SHADOWSTAGE_NONE;
1216 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1218 int i, ix1, iy1, ix2, iy2;
1219 float x1, y1, x2, y2, x, y, f;
1220 vec3_t smins, smaxs;
1222 if (!r_shadow_scissor.integer)
1224 // if view is inside the box, just say yes it's visible
1225 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1227 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1230 for (i = 0;i < 3;i++)
1232 if (r_viewforward[i] >= 0)
1243 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1244 if (DotProduct(r_viewforward, v2) <= f)
1246 // entirely behind nearclip plane
1249 if (DotProduct(r_viewforward, v) >= f)
1251 // entirely infront of nearclip plane
1252 x1 = y1 = x2 = y2 = 0;
1253 for (i = 0;i < 8;i++)
1255 v[0] = (i & 1) ? mins[0] : maxs[0];
1256 v[1] = (i & 2) ? mins[1] : maxs[1];
1257 v[2] = (i & 4) ? mins[2] : maxs[2];
1259 GL_TransformToScreen(v, v2);
1260 //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]);
1279 // clipped by nearclip plane
1280 // this is nasty and crude...
1281 // create viewspace bbox
1282 for (i = 0;i < 8;i++)
1284 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1285 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1286 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1287 v2[0] = -DotProduct(v, r_viewleft);
1288 v2[1] = DotProduct(v, r_viewup);
1289 v2[2] = DotProduct(v, r_viewforward);
1292 if (smins[0] > v2[0]) smins[0] = v2[0];
1293 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1294 if (smins[1] > v2[1]) smins[1] = v2[1];
1295 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1296 if (smins[2] > v2[2]) smins[2] = v2[2];
1297 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1301 smins[0] = smaxs[0] = v2[0];
1302 smins[1] = smaxs[1] = v2[1];
1303 smins[2] = smaxs[2] = v2[2];
1306 // now we have a bbox in viewspace
1307 // clip it to the view plane
1310 // return true if that culled the box
1311 if (smins[2] >= smaxs[2])
1313 // ok some of it is infront of the view, transform each corner back to
1314 // worldspace and then to screenspace and make screen rect
1315 // initialize these variables just to avoid compiler warnings
1316 x1 = y1 = x2 = y2 = 0;
1317 for (i = 0;i < 8;i++)
1319 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1320 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1321 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1322 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1323 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1324 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1326 GL_TransformToScreen(v, v2);
1327 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1344 // this code doesn't handle boxes with any points behind view properly
1345 x1 = 1000;x2 = -1000;
1346 y1 = 1000;y2 = -1000;
1347 for (i = 0;i < 8;i++)
1349 v[0] = (i & 1) ? mins[0] : maxs[0];
1350 v[1] = (i & 2) ? mins[1] : maxs[1];
1351 v[2] = (i & 4) ? mins[2] : maxs[2];
1353 GL_TransformToScreen(v, v2);
1354 //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]);
1372 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1373 if (ix1 < r_view_x) ix1 = r_view_x;
1374 if (iy1 < r_view_y) iy1 = r_view_y;
1375 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1376 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1377 if (ix2 <= ix1 || iy2 <= iy1)
1379 // set up the scissor rectangle
1380 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1381 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1382 //qglEnable(GL_SCISSOR_TEST);
1387 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1389 float *color4f = varray_color4f;
1390 float dist, dot, intensity, v[3], n[3];
1391 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1393 Matrix4x4_Transform(m, vertex3f, v);
1394 if ((dist = DotProduct(v, v)) < 1)
1396 Matrix4x4_Transform3x3(m, normal3f, n);
1397 if ((dot = DotProduct(n, v)) > 0)
1400 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1401 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1402 VectorScale(lightcolor, intensity, color4f);
1407 VectorClear(color4f);
1413 VectorClear(color4f);
1419 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1421 float *color4f = varray_color4f;
1422 float dist, dot, intensity, v[3], n[3];
1423 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1425 Matrix4x4_Transform(m, vertex3f, v);
1426 if ((dist = fabs(v[2])) < 1)
1428 Matrix4x4_Transform3x3(m, normal3f, n);
1429 if ((dot = DotProduct(n, v)) > 0)
1431 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1432 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1433 VectorScale(lightcolor, intensity, color4f);
1438 VectorClear(color4f);
1444 VectorClear(color4f);
1450 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1452 float *color4f = varray_color4f;
1453 float dot, intensity, v[3], n[3];
1454 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1456 Matrix4x4_Transform(m, vertex3f, v);
1457 Matrix4x4_Transform3x3(m, normal3f, n);
1458 if ((dot = DotProduct(n, v)) > 0)
1460 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1461 VectorScale(lightcolor, intensity, color4f);
1466 VectorClear(color4f);
1472 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1474 float *color4f = varray_color4f;
1475 float dist, intensity, v[3];
1476 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1478 Matrix4x4_Transform(m, vertex3f, v);
1479 if ((dist = DotProduct(v, v)) < 1)
1482 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1483 VectorScale(lightcolor, intensity, color4f);
1488 VectorClear(color4f);
1494 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1496 float *color4f = varray_color4f;
1497 float dist, intensity, v[3];
1498 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1500 Matrix4x4_Transform(m, vertex3f, v);
1501 if ((dist = fabs(v[2])) < 1)
1503 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1504 VectorScale(lightcolor, intensity, color4f);
1509 VectorClear(color4f);
1515 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1516 #define USETEXMATRIX
1518 #ifndef USETEXMATRIX
1519 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1520 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1521 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1525 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1526 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1527 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1534 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1538 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1539 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1547 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)
1551 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1553 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1554 // the cubemap normalizes this for us
1555 out3f[0] = DotProduct(svector3f, lightdir);
1556 out3f[1] = DotProduct(tvector3f, lightdir);
1557 out3f[2] = DotProduct(normal3f, lightdir);
1561 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)
1564 float lightdir[3], eyedir[3], halfdir[3];
1565 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1567 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1568 VectorNormalizeFast(lightdir);
1569 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1570 VectorNormalizeFast(eyedir);
1571 VectorAdd(lightdir, eyedir, halfdir);
1572 // the cubemap normalizes this for us
1573 out3f[0] = DotProduct(svector3f, halfdir);
1574 out3f[1] = DotProduct(tvector3f, halfdir);
1575 out3f[2] = DotProduct(normal3f, halfdir);
1579 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)
1582 float color[3], color2[3], colorscale;
1584 // FIXME: support EF_NODEPTHTEST
1585 GL_DepthMask(false);
1588 bumptexture = r_shadow_blankbumptexture;
1589 specularscale *= r_shadow_glossintensity.value;
1592 if (r_shadow_gloss.integer >= 2)
1594 glosstexture = r_shadow_blankglosstexture;
1595 specularscale *= r_shadow_gloss2intensity.value;
1599 glosstexture = r_shadow_blankblacktexture;
1603 if (r_shadow_gloss.integer < 1)
1606 lightcubemap = r_shadow_blankwhitecubetexture;
1607 if (ambientscale + diffusescale + specularscale < 0.01)
1609 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1611 unsigned int perm, prog;
1612 // GLSL shader path (GFFX5200, Radeon 9500)
1613 memset(&m, 0, sizeof(m));
1614 m.pointer_vertex = vertex3f;
1615 m.pointer_texcoord[0] = texcoord2f;
1616 m.pointer_texcoord3f[1] = svector3f;
1617 m.pointer_texcoord3f[2] = tvector3f;
1618 m.pointer_texcoord3f[3] = normal3f;
1619 m.tex[0] = R_GetTexture(bumptexture);
1620 m.tex[1] = R_GetTexture(basetexture);
1621 m.tex[2] = R_GetTexture(glosstexture);
1622 m.texcubemap[3] = R_GetTexture(lightcubemap);
1623 // TODO: support fog (after renderer is converted to texture fog)
1624 m.tex[4] = R_GetTexture(r_shadow_blankwhitetexture);
1625 m.texmatrix[3] = *matrix_modeltolight;
1627 GL_BlendFunc(GL_ONE, GL_ONE);
1628 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1631 // only add a feature to the permutation if that permutation exists
1632 // (otherwise it might end up not using a shader at all, which looks
1633 // worse than using less features)
1634 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1635 perm |= SHADERPERMUTATION_SPECULAR;
1636 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1637 // perm |= SHADERPERMUTATION_FOG;
1638 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1639 perm |= SHADERPERMUTATION_CUBEFILTER;
1640 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1641 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1642 prog = r_shadow_program_light[perm];
1643 qglUseProgramObjectARB(prog);CHECKGLERROR
1644 // TODO: support fog (after renderer is converted to texture fog)
1645 if (perm & SHADERPERMUTATION_FOG)
1647 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1649 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1650 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1651 if (perm & SHADERPERMUTATION_SPECULAR)
1653 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1654 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1656 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);CHECKGLERROR
1657 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1658 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1660 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1662 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1664 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1665 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1668 GL_LockArrays(0, numverts);
1669 R_Mesh_Draw(numverts, numtriangles, elements);
1671 c_rt_lighttris += numtriangles;
1672 GL_LockArrays(0, 0);
1673 qglUseProgramObjectARB(0);
1674 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1675 qglBegin(GL_TRIANGLES);
1679 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1682 bumptexture = r_shadow_blankbumptexture;
1684 glosstexture = r_shadow_blankglosstexture;
1688 colorscale = ambientscale;
1689 // colorscale accounts for how much we multiply the brightness
1692 // mult is how many times the final pass of the lighting will be
1693 // performed to get more brightness than otherwise possible.
1695 // Limit mult to 64 for sanity sake.
1696 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1698 // 3 3D combine path (Geforce3, Radeon 8500)
1699 memset(&m, 0, sizeof(m));
1700 m.pointer_vertex = vertex3f;
1701 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1703 m.pointer_texcoord3f[0] = vertex3f;
1704 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1706 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1707 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1709 m.tex[1] = R_GetTexture(basetexture);
1710 m.pointer_texcoord[1] = texcoord2f;
1711 m.texcubemap[2] = R_GetTexture(lightcubemap);
1713 m.pointer_texcoord3f[2] = vertex3f;
1714 m.texmatrix[2] = *matrix_modeltolight;
1716 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1717 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1719 GL_BlendFunc(GL_ONE, GL_ONE);
1721 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1723 // 2 3D combine path (Geforce3, original Radeon)
1724 memset(&m, 0, sizeof(m));
1725 m.pointer_vertex = vertex3f;
1726 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1728 m.pointer_texcoord3f[0] = vertex3f;
1729 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1731 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1732 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1734 m.tex[1] = R_GetTexture(basetexture);
1735 m.pointer_texcoord[1] = texcoord2f;
1736 GL_BlendFunc(GL_ONE, GL_ONE);
1738 else if (r_textureunits.integer >= 4 && lightcubemap)
1740 // 4 2D combine path (Geforce3, Radeon 8500)
1741 memset(&m, 0, sizeof(m));
1742 m.pointer_vertex = vertex3f;
1743 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1745 m.pointer_texcoord3f[0] = vertex3f;
1746 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1748 m.pointer_texcoord[0] = varray_texcoord2f[0];
1749 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1751 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1753 m.pointer_texcoord3f[1] = vertex3f;
1754 m.texmatrix[1] = *matrix_modeltoattenuationz;
1756 m.pointer_texcoord[1] = varray_texcoord2f[1];
1757 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1759 m.tex[2] = R_GetTexture(basetexture);
1760 m.pointer_texcoord[2] = texcoord2f;
1763 m.texcubemap[3] = R_GetTexture(lightcubemap);
1765 m.pointer_texcoord3f[3] = vertex3f;
1766 m.texmatrix[3] = *matrix_modeltolight;
1768 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1769 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1772 GL_BlendFunc(GL_ONE, GL_ONE);
1774 else if (r_textureunits.integer >= 3 && !lightcubemap)
1776 // 3 2D combine path (Geforce3, original Radeon)
1777 memset(&m, 0, sizeof(m));
1778 m.pointer_vertex = vertex3f;
1779 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1781 m.pointer_texcoord3f[0] = vertex3f;
1782 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1784 m.pointer_texcoord[0] = varray_texcoord2f[0];
1785 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1787 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1789 m.pointer_texcoord3f[1] = vertex3f;
1790 m.texmatrix[1] = *matrix_modeltoattenuationz;
1792 m.pointer_texcoord[1] = varray_texcoord2f[1];
1793 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1795 m.tex[2] = R_GetTexture(basetexture);
1796 m.pointer_texcoord[2] = texcoord2f;
1797 GL_BlendFunc(GL_ONE, GL_ONE);
1801 // 2/2/2 2D combine path (any dot3 card)
1802 memset(&m, 0, sizeof(m));
1803 m.pointer_vertex = vertex3f;
1804 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1806 m.pointer_texcoord3f[0] = vertex3f;
1807 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1809 m.pointer_texcoord[0] = varray_texcoord2f[0];
1810 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1812 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1814 m.pointer_texcoord3f[1] = vertex3f;
1815 m.texmatrix[1] = *matrix_modeltoattenuationz;
1817 m.pointer_texcoord[1] = varray_texcoord2f[1];
1818 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1821 GL_ColorMask(0,0,0,1);
1822 GL_BlendFunc(GL_ONE, GL_ZERO);
1823 GL_LockArrays(0, numverts);
1824 R_Mesh_Draw(numverts, numtriangles, elements);
1825 GL_LockArrays(0, 0);
1827 c_rt_lighttris += numtriangles;
1829 memset(&m, 0, sizeof(m));
1830 m.pointer_vertex = vertex3f;
1831 m.tex[0] = R_GetTexture(basetexture);
1832 m.pointer_texcoord[0] = texcoord2f;
1835 m.texcubemap[1] = R_GetTexture(lightcubemap);
1837 m.pointer_texcoord3f[1] = vertex3f;
1838 m.texmatrix[1] = *matrix_modeltolight;
1840 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1841 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1844 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1846 // this final code is shared
1848 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1849 VectorScale(lightcolor, colorscale, color2);
1850 GL_LockArrays(0, numverts);
1851 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1853 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1854 R_Mesh_Draw(numverts, numtriangles, elements);
1856 c_rt_lighttris += numtriangles;
1858 GL_LockArrays(0, 0);
1863 colorscale = diffusescale;
1864 // colorscale accounts for how much we multiply the brightness
1867 // mult is how many times the final pass of the lighting will be
1868 // performed to get more brightness than otherwise possible.
1870 // Limit mult to 64 for sanity sake.
1871 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1873 // 3/2 3D combine path (Geforce3, Radeon 8500)
1874 memset(&m, 0, sizeof(m));
1875 m.pointer_vertex = vertex3f;
1876 m.tex[0] = R_GetTexture(bumptexture);
1877 m.texcombinergb[0] = GL_REPLACE;
1878 m.pointer_texcoord[0] = texcoord2f;
1879 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1880 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1881 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1882 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1883 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1885 m.pointer_texcoord3f[2] = vertex3f;
1886 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1888 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1889 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1892 GL_ColorMask(0,0,0,1);
1893 GL_BlendFunc(GL_ONE, GL_ZERO);
1894 GL_LockArrays(0, numverts);
1895 R_Mesh_Draw(numverts, numtriangles, elements);
1896 GL_LockArrays(0, 0);
1898 c_rt_lighttris += numtriangles;
1900 memset(&m, 0, sizeof(m));
1901 m.pointer_vertex = vertex3f;
1902 m.tex[0] = R_GetTexture(basetexture);
1903 m.pointer_texcoord[0] = texcoord2f;
1906 m.texcubemap[1] = R_GetTexture(lightcubemap);
1908 m.pointer_texcoord3f[1] = vertex3f;
1909 m.texmatrix[1] = *matrix_modeltolight;
1911 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1912 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1915 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1917 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1919 // 1/2/2 3D combine path (original Radeon)
1920 memset(&m, 0, sizeof(m));
1921 m.pointer_vertex = vertex3f;
1922 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1924 m.pointer_texcoord3f[0] = vertex3f;
1925 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1927 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1928 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1931 GL_ColorMask(0,0,0,1);
1932 GL_BlendFunc(GL_ONE, GL_ZERO);
1933 GL_LockArrays(0, numverts);
1934 R_Mesh_Draw(numverts, numtriangles, elements);
1935 GL_LockArrays(0, 0);
1937 c_rt_lighttris += numtriangles;
1939 memset(&m, 0, sizeof(m));
1940 m.pointer_vertex = vertex3f;
1941 m.tex[0] = R_GetTexture(bumptexture);
1942 m.texcombinergb[0] = GL_REPLACE;
1943 m.pointer_texcoord[0] = texcoord2f;
1944 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1945 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1946 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1947 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1949 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1950 GL_LockArrays(0, numverts);
1951 R_Mesh_Draw(numverts, numtriangles, elements);
1952 GL_LockArrays(0, 0);
1954 c_rt_lighttris += numtriangles;
1956 memset(&m, 0, sizeof(m));
1957 m.pointer_vertex = vertex3f;
1958 m.tex[0] = R_GetTexture(basetexture);
1959 m.pointer_texcoord[0] = texcoord2f;
1962 m.texcubemap[1] = R_GetTexture(lightcubemap);
1964 m.pointer_texcoord3f[1] = vertex3f;
1965 m.texmatrix[1] = *matrix_modeltolight;
1967 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1968 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1971 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1973 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1975 // 2/2 3D combine path (original Radeon)
1976 memset(&m, 0, sizeof(m));
1977 m.pointer_vertex = vertex3f;
1978 m.tex[0] = R_GetTexture(bumptexture);
1979 m.texcombinergb[0] = GL_REPLACE;
1980 m.pointer_texcoord[0] = texcoord2f;
1981 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1982 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1983 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1984 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1986 GL_ColorMask(0,0,0,1);
1987 GL_BlendFunc(GL_ONE, GL_ZERO);
1988 GL_LockArrays(0, numverts);
1989 R_Mesh_Draw(numverts, numtriangles, elements);
1990 GL_LockArrays(0, 0);
1992 c_rt_lighttris += numtriangles;
1994 memset(&m, 0, sizeof(m));
1995 m.pointer_vertex = vertex3f;
1996 m.tex[0] = R_GetTexture(basetexture);
1997 m.pointer_texcoord[0] = texcoord2f;
1998 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2000 m.pointer_texcoord3f[1] = vertex3f;
2001 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2003 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2004 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2006 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2008 else if (r_textureunits.integer >= 4)
2010 // 4/2 2D combine path (Geforce3, Radeon 8500)
2011 memset(&m, 0, sizeof(m));
2012 m.pointer_vertex = vertex3f;
2013 m.tex[0] = R_GetTexture(bumptexture);
2014 m.texcombinergb[0] = GL_REPLACE;
2015 m.pointer_texcoord[0] = texcoord2f;
2016 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2017 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2018 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2019 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2020 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2022 m.pointer_texcoord3f[2] = vertex3f;
2023 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2025 m.pointer_texcoord[2] = varray_texcoord2f[2];
2026 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2028 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2030 m.pointer_texcoord3f[3] = vertex3f;
2031 m.texmatrix[3] = *matrix_modeltoattenuationz;
2033 m.pointer_texcoord[3] = varray_texcoord2f[3];
2034 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2037 GL_ColorMask(0,0,0,1);
2038 GL_BlendFunc(GL_ONE, GL_ZERO);
2039 GL_LockArrays(0, numverts);
2040 R_Mesh_Draw(numverts, numtriangles, elements);
2041 GL_LockArrays(0, 0);
2043 c_rt_lighttris += numtriangles;
2045 memset(&m, 0, sizeof(m));
2046 m.pointer_vertex = vertex3f;
2047 m.tex[0] = R_GetTexture(basetexture);
2048 m.pointer_texcoord[0] = texcoord2f;
2051 m.texcubemap[1] = R_GetTexture(lightcubemap);
2053 m.pointer_texcoord3f[1] = vertex3f;
2054 m.texmatrix[1] = *matrix_modeltolight;
2056 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2057 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2060 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2064 // 2/2/2 2D combine path (any dot3 card)
2065 memset(&m, 0, sizeof(m));
2066 m.pointer_vertex = vertex3f;
2067 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2069 m.pointer_texcoord3f[0] = vertex3f;
2070 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2072 m.pointer_texcoord[0] = varray_texcoord2f[0];
2073 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2075 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2077 m.pointer_texcoord3f[1] = vertex3f;
2078 m.texmatrix[1] = *matrix_modeltoattenuationz;
2080 m.pointer_texcoord[1] = varray_texcoord2f[1];
2081 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2084 GL_ColorMask(0,0,0,1);
2085 GL_BlendFunc(GL_ONE, GL_ZERO);
2086 GL_LockArrays(0, numverts);
2087 R_Mesh_Draw(numverts, numtriangles, elements);
2088 GL_LockArrays(0, 0);
2090 c_rt_lighttris += numtriangles;
2092 memset(&m, 0, sizeof(m));
2093 m.pointer_vertex = vertex3f;
2094 m.tex[0] = R_GetTexture(bumptexture);
2095 m.texcombinergb[0] = GL_REPLACE;
2096 m.pointer_texcoord[0] = texcoord2f;
2097 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2098 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2099 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2100 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2102 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2103 GL_LockArrays(0, numverts);
2104 R_Mesh_Draw(numverts, numtriangles, elements);
2105 GL_LockArrays(0, 0);
2107 c_rt_lighttris += numtriangles;
2109 memset(&m, 0, sizeof(m));
2110 m.pointer_vertex = vertex3f;
2111 m.tex[0] = R_GetTexture(basetexture);
2112 m.pointer_texcoord[0] = texcoord2f;
2115 m.texcubemap[1] = R_GetTexture(lightcubemap);
2117 m.pointer_texcoord3f[1] = vertex3f;
2118 m.texmatrix[1] = *matrix_modeltolight;
2120 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2121 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2124 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2126 // this final code is shared
2128 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2129 VectorScale(lightcolor, colorscale, color2);
2130 GL_LockArrays(0, numverts);
2131 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2133 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2134 R_Mesh_Draw(numverts, numtriangles, elements);
2136 c_rt_lighttris += numtriangles;
2138 GL_LockArrays(0, 0);
2140 if (specularscale && glosstexture != r_shadow_blankblacktexture)
2142 // FIXME: detect blendsquare!
2143 //if (gl_support_blendsquare)
2145 colorscale = specularscale;
2147 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2149 // 2/0/0/1/2 3D combine blendsquare path
2150 memset(&m, 0, sizeof(m));
2151 m.pointer_vertex = vertex3f;
2152 m.tex[0] = R_GetTexture(bumptexture);
2153 m.pointer_texcoord[0] = texcoord2f;
2154 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2155 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2156 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2157 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2159 GL_ColorMask(0,0,0,1);
2160 // this squares the result
2161 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2162 GL_LockArrays(0, numverts);
2163 R_Mesh_Draw(numverts, numtriangles, elements);
2164 GL_LockArrays(0, 0);
2166 c_rt_lighttris += numtriangles;
2168 memset(&m, 0, sizeof(m));
2169 m.pointer_vertex = vertex3f;
2171 GL_LockArrays(0, numverts);
2172 // square alpha in framebuffer a few times to make it shiny
2173 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2174 // these comments are a test run through this math for intensity 0.5
2175 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2176 // 0.25 * 0.25 = 0.0625 (this is another pass)
2177 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2178 R_Mesh_Draw(numverts, numtriangles, elements);
2180 c_rt_lighttris += numtriangles;
2181 R_Mesh_Draw(numverts, numtriangles, elements);
2183 c_rt_lighttris += numtriangles;
2184 GL_LockArrays(0, 0);
2186 memset(&m, 0, sizeof(m));
2187 m.pointer_vertex = vertex3f;
2188 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2190 m.pointer_texcoord3f[0] = vertex3f;
2191 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2193 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2194 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2197 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2198 GL_LockArrays(0, numverts);
2199 R_Mesh_Draw(numverts, numtriangles, elements);
2200 GL_LockArrays(0, 0);
2202 c_rt_lighttris += numtriangles;
2204 memset(&m, 0, sizeof(m));
2205 m.pointer_vertex = vertex3f;
2206 m.tex[0] = R_GetTexture(glosstexture);
2207 m.pointer_texcoord[0] = texcoord2f;
2210 m.texcubemap[1] = R_GetTexture(lightcubemap);
2212 m.pointer_texcoord3f[1] = vertex3f;
2213 m.texmatrix[1] = *matrix_modeltolight;
2215 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2216 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2219 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2221 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2223 // 2/0/0/2 3D combine blendsquare path
2224 memset(&m, 0, sizeof(m));
2225 m.pointer_vertex = vertex3f;
2226 m.tex[0] = R_GetTexture(bumptexture);
2227 m.pointer_texcoord[0] = texcoord2f;
2228 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2229 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2230 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2231 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2233 GL_ColorMask(0,0,0,1);
2234 // this squares the result
2235 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2236 GL_LockArrays(0, numverts);
2237 R_Mesh_Draw(numverts, numtriangles, elements);
2238 GL_LockArrays(0, 0);
2240 c_rt_lighttris += numtriangles;
2242 memset(&m, 0, sizeof(m));
2243 m.pointer_vertex = vertex3f;
2245 GL_LockArrays(0, numverts);
2246 // square alpha in framebuffer a few times to make it shiny
2247 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2248 // these comments are a test run through this math for intensity 0.5
2249 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2250 // 0.25 * 0.25 = 0.0625 (this is another pass)
2251 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2252 R_Mesh_Draw(numverts, numtriangles, elements);
2254 c_rt_lighttris += numtriangles;
2255 R_Mesh_Draw(numverts, numtriangles, elements);
2257 c_rt_lighttris += numtriangles;
2258 GL_LockArrays(0, 0);
2260 memset(&m, 0, sizeof(m));
2261 m.pointer_vertex = vertex3f;
2262 m.tex[0] = R_GetTexture(glosstexture);
2263 m.pointer_texcoord[0] = texcoord2f;
2264 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2266 m.pointer_texcoord3f[1] = vertex3f;
2267 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2269 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2270 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2272 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2276 // 2/0/0/2/2 2D combine blendsquare path
2277 memset(&m, 0, sizeof(m));
2278 m.pointer_vertex = vertex3f;
2279 m.tex[0] = R_GetTexture(bumptexture);
2280 m.pointer_texcoord[0] = texcoord2f;
2281 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2282 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2283 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2284 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2286 GL_ColorMask(0,0,0,1);
2287 // this squares the result
2288 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2289 GL_LockArrays(0, numverts);
2290 R_Mesh_Draw(numverts, numtriangles, elements);
2291 GL_LockArrays(0, 0);
2293 c_rt_lighttris += numtriangles;
2295 memset(&m, 0, sizeof(m));
2296 m.pointer_vertex = vertex3f;
2298 GL_LockArrays(0, numverts);
2299 // square alpha in framebuffer a few times to make it shiny
2300 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2301 // these comments are a test run through this math for intensity 0.5
2302 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2303 // 0.25 * 0.25 = 0.0625 (this is another pass)
2304 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2305 R_Mesh_Draw(numverts, numtriangles, elements);
2307 c_rt_lighttris += numtriangles;
2308 R_Mesh_Draw(numverts, numtriangles, elements);
2310 c_rt_lighttris += numtriangles;
2311 GL_LockArrays(0, 0);
2313 memset(&m, 0, sizeof(m));
2314 m.pointer_vertex = vertex3f;
2315 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2317 m.pointer_texcoord3f[0] = vertex3f;
2318 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2320 m.pointer_texcoord[0] = varray_texcoord2f[0];
2321 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2323 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2325 m.pointer_texcoord3f[1] = vertex3f;
2326 m.texmatrix[1] = *matrix_modeltoattenuationz;
2328 m.pointer_texcoord[1] = varray_texcoord2f[1];
2329 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2332 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2333 GL_LockArrays(0, numverts);
2334 R_Mesh_Draw(numverts, numtriangles, elements);
2335 GL_LockArrays(0, 0);
2337 c_rt_lighttris += numtriangles;
2339 memset(&m, 0, sizeof(m));
2340 m.pointer_vertex = vertex3f;
2341 m.tex[0] = R_GetTexture(glosstexture);
2342 m.pointer_texcoord[0] = texcoord2f;
2345 m.texcubemap[1] = R_GetTexture(lightcubemap);
2347 m.pointer_texcoord3f[1] = vertex3f;
2348 m.texmatrix[1] = *matrix_modeltolight;
2350 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2351 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2354 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2357 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2358 VectorScale(lightcolor, colorscale, color2);
2359 GL_LockArrays(0, numverts);
2360 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2362 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2363 R_Mesh_Draw(numverts, numtriangles, elements);
2365 c_rt_lighttris += numtriangles;
2367 GL_LockArrays(0, 0);
2375 GL_BlendFunc(GL_ONE, GL_ONE);
2376 VectorScale(lightcolor, ambientscale, color2);
2377 memset(&m, 0, sizeof(m));
2378 m.pointer_vertex = vertex3f;
2379 m.tex[0] = R_GetTexture(basetexture);
2380 m.pointer_texcoord[0] = texcoord2f;
2381 if (r_textureunits.integer >= 2)
2384 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2386 m.pointer_texcoord3f[1] = vertex3f;
2387 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2389 m.pointer_texcoord[1] = varray_texcoord2f[1];
2390 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2392 if (r_textureunits.integer >= 3)
2394 // Geforce3/Radeon class but not using dot3
2395 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2397 m.pointer_texcoord3f[2] = vertex3f;
2398 m.texmatrix[2] = *matrix_modeltoattenuationz;
2400 m.pointer_texcoord[2] = varray_texcoord2f[2];
2401 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2405 if (r_textureunits.integer >= 3)
2406 m.pointer_color = NULL;
2408 m.pointer_color = varray_color4f;
2410 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2412 color[0] = bound(0, color2[0], 1);
2413 color[1] = bound(0, color2[1], 1);
2414 color[2] = bound(0, color2[2], 1);
2415 if (r_textureunits.integer >= 3)
2416 GL_Color(color[0], color[1], color[2], 1);
2417 else if (r_textureunits.integer >= 2)
2418 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2420 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2421 GL_LockArrays(0, numverts);
2422 R_Mesh_Draw(numverts, numtriangles, elements);
2423 GL_LockArrays(0, 0);
2425 c_rt_lighttris += numtriangles;
2430 GL_BlendFunc(GL_ONE, GL_ONE);
2431 VectorScale(lightcolor, diffusescale, color2);
2432 memset(&m, 0, sizeof(m));
2433 m.pointer_vertex = vertex3f;
2434 m.pointer_color = varray_color4f;
2435 m.tex[0] = R_GetTexture(basetexture);
2436 m.pointer_texcoord[0] = texcoord2f;
2437 if (r_textureunits.integer >= 2)
2440 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2442 m.pointer_texcoord3f[1] = vertex3f;
2443 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2445 m.pointer_texcoord[1] = varray_texcoord2f[1];
2446 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2448 if (r_textureunits.integer >= 3)
2450 // Geforce3/Radeon class but not using dot3
2451 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2453 m.pointer_texcoord3f[2] = vertex3f;
2454 m.texmatrix[2] = *matrix_modeltoattenuationz;
2456 m.pointer_texcoord[2] = varray_texcoord2f[2];
2457 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2462 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2464 color[0] = bound(0, color2[0], 1);
2465 color[1] = bound(0, color2[1], 1);
2466 color[2] = bound(0, color2[2], 1);
2467 if (r_textureunits.integer >= 3)
2468 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2469 else if (r_textureunits.integer >= 2)
2470 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2472 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2473 GL_LockArrays(0, numverts);
2474 R_Mesh_Draw(numverts, numtriangles, elements);
2475 GL_LockArrays(0, 0);
2477 c_rt_lighttris += numtriangles;
2483 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2487 R_RTLight_Uncompile(rtlight);
2488 memset(rtlight, 0, sizeof(*rtlight));
2490 VectorCopy(light->origin, rtlight->shadoworigin);
2491 VectorCopy(light->color, rtlight->color);
2492 rtlight->radius = light->radius;
2493 //rtlight->cullradius = rtlight->radius;
2494 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2495 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2496 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2497 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2498 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2499 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2500 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2501 rtlight->cubemapname[0] = 0;
2502 if (light->cubemapname[0])
2503 strcpy(rtlight->cubemapname, light->cubemapname);
2504 else if (light->cubemapnum > 0)
2505 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2506 rtlight->shadow = light->shadow;
2507 rtlight->corona = light->corona;
2508 rtlight->style = light->style;
2509 rtlight->isstatic = isstatic;
2510 rtlight->coronasizescale = light->coronasizescale;
2511 rtlight->ambientscale = light->ambientscale;
2512 rtlight->diffusescale = light->diffusescale;
2513 rtlight->specularscale = light->specularscale;
2514 rtlight->flags = light->flags;
2515 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2516 // ConcatScale won't work here because this needs to scale rotate and
2517 // translate, not just rotate
2518 scale = 1.0f / rtlight->radius;
2519 for (k = 0;k < 3;k++)
2520 for (j = 0;j < 4;j++)
2521 rtlight->matrix_worldtolight.m[k][j] *= scale;
2522 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2523 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2525 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2526 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2527 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2528 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2531 // compiles rtlight geometry
2532 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2533 void R_RTLight_Compile(rtlight_t *rtlight)
2535 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2536 entity_render_t *ent = r_refdef.worldentity;
2537 model_t *model = r_refdef.worldmodel;
2539 // compile the light
2540 rtlight->compiled = true;
2541 rtlight->static_numclusters = 0;
2542 rtlight->static_numclusterpvsbytes = 0;
2543 rtlight->static_clusterlist = NULL;
2544 rtlight->static_clusterpvs = NULL;
2545 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2546 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2547 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2548 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2549 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2550 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2552 if (model && model->GetLightInfo)
2554 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2555 r_shadow_compilingrtlight = rtlight;
2556 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2557 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2558 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);
2559 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2560 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2563 rtlight->static_numclusters = numclusters;
2564 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2565 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2566 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2568 if (model->DrawShadowVolume && rtlight->shadow)
2570 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2571 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2572 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2574 if (model->DrawLight)
2576 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2577 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);
2578 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2580 // switch back to rendering when DrawShadowVolume or DrawLight is called
2581 r_shadow_compilingrtlight = NULL;
2585 // use smallest available cullradius - box radius or light radius
2586 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2587 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2591 if (rtlight->static_meshchain_shadow)
2594 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2597 shadowtris += mesh->numtriangles;
2603 if (rtlight->static_meshchain_light)
2606 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2609 lighttris += mesh->numtriangles;
2613 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);
2616 void R_RTLight_Uncompile(rtlight_t *rtlight)
2618 if (rtlight->compiled)
2620 if (rtlight->static_meshchain_shadow)
2621 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2622 rtlight->static_meshchain_shadow = NULL;
2623 if (rtlight->static_meshchain_light)
2624 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2625 rtlight->static_meshchain_light = NULL;
2626 if (rtlight->static_clusterlist)
2627 Mem_Free(rtlight->static_clusterlist);
2628 rtlight->static_clusterlist = NULL;
2629 if (rtlight->static_clusterpvs)
2630 Mem_Free(rtlight->static_clusterpvs);
2631 rtlight->static_clusterpvs = NULL;
2632 rtlight->static_numclusters = 0;
2633 rtlight->static_numclusterpvsbytes = 0;
2634 rtlight->compiled = false;
2638 void R_Shadow_UncompileWorldLights(void)
2641 for (light = r_shadow_worldlightchain;light;light = light->next)
2642 R_RTLight_Uncompile(&light->rtlight);
2645 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2647 int i, shadow, usestencil;
2648 entity_render_t *ent;
2650 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2651 rtexture_t *cubemaptexture;
2652 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2653 int numclusters, numsurfaces;
2654 int *clusterlist, *surfacelist;
2656 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2660 // skip lights that don't light (corona only lights)
2661 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2664 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2665 VectorScale(rtlight->color, f, lightcolor);
2666 if (VectorLength2(lightcolor) < 0.01)
2669 if (rtlight->selected)
2671 f = 2 + sin(realtime * M_PI * 4.0);
2672 VectorScale(lightcolor, f, lightcolor);
2676 // loading is done before visibility checks because loading should happen
2677 // all at once at the start of a level, not when it stalls gameplay.
2678 // (especially important to benchmarks)
2679 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2680 R_RTLight_Compile(rtlight);
2681 if (rtlight->cubemapname[0])
2682 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2684 cubemaptexture = NULL;
2686 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2687 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2688 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2689 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2690 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2691 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2692 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2699 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2701 // compiled light, world available and can receive realtime lighting
2702 // retrieve cluster information
2703 numclusters = rtlight->static_numclusters;
2704 clusterlist = rtlight->static_clusterlist;
2705 clusterpvs = rtlight->static_clusterpvs;
2706 VectorCopy(rtlight->cullmins, cullmins);
2707 VectorCopy(rtlight->cullmaxs, cullmaxs);
2709 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2711 // dynamic light, world available and can receive realtime lighting
2712 // if the light box is offscreen, skip it right away
2713 if (R_CullBox(cullmins, cullmaxs))
2715 // calculate lit surfaces and clusters
2716 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2717 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2718 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);
2719 clusterlist = r_shadow_buffer_clusterlist;
2720 clusterpvs = r_shadow_buffer_clusterpvs;
2721 surfacelist = r_shadow_buffer_surfacelist;
2723 // if the reduced cluster bounds are offscreen, skip it
2724 if (R_CullBox(cullmins, cullmaxs))
2726 // check if light is illuminating any visible clusters
2729 for (i = 0;i < numclusters;i++)
2730 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2732 if (i == numclusters)
2735 // set up a scissor rectangle for this light
2736 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2739 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2742 if (shadow && (gl_stencil || visiblevolumes))
2744 if (!visiblevolumes)
2746 R_Shadow_Stage_ShadowVolumes();
2749 ent = &cl_entities[0].render;
2750 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2752 memset(&m, 0, sizeof(m));
2753 R_Mesh_Matrix(&ent->matrix);
2754 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2756 m.pointer_vertex = mesh->vertex3f;
2758 GL_LockArrays(0, mesh->numverts);
2759 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2761 // increment stencil if backface is behind depthbuffer
2762 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2763 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2764 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2765 c_rtcached_shadowmeshes++;
2766 c_rtcached_shadowtris += mesh->numtriangles;
2767 // decrement stencil if frontface is behind depthbuffer
2768 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2769 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2771 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2772 c_rtcached_shadowmeshes++;
2773 c_rtcached_shadowtris += mesh->numtriangles;
2774 GL_LockArrays(0, 0);
2777 else if (numsurfaces)
2779 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2780 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2782 if (r_drawentities.integer)
2784 for (i = 0;i < r_refdef.numentities;i++)
2786 ent = r_refdef.entities[i];
2788 if (r_shadow_cull.integer)
2790 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2792 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2795 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2797 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2798 // light emitting entities should not cast their own shadow
2799 if (VectorLength2(relativelightorigin) < 0.1)
2801 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2802 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2803 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2804 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2805 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2806 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2807 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2812 if (!visiblevolumes)
2814 R_Shadow_Stage_Light(usestencil);
2816 ent = &cl_entities[0].render;
2817 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2819 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2820 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2821 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2822 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2823 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2824 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2825 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2826 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2827 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2829 R_Mesh_Matrix(&ent->matrix);
2830 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2831 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);
2834 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2836 if (r_drawentities.integer)
2838 for (i = 0;i < r_refdef.numentities;i++)
2840 ent = r_refdef.entities[i];
2841 // can't draw transparent entity lighting here because
2842 // transparent meshes are deferred for later
2843 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)
2845 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2846 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2847 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2848 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2849 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2850 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2851 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2852 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2853 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);
2860 void R_ShadowVolumeLighting(int visiblevolumes)
2866 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2867 R_Shadow_EditLights_Reload_f();
2871 memset(&m, 0, sizeof(m));
2874 GL_BlendFunc(GL_ONE, GL_ONE);
2875 GL_DepthMask(false);
2876 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2877 qglDisable(GL_CULL_FACE);
2878 GL_Color(0.0, 0.0125, 0.1, 1);
2881 R_Shadow_Stage_Begin();
2882 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2883 if (r_shadow_debuglight.integer >= 0)
2885 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2886 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2887 R_DrawRTLight(&light->rtlight, visiblevolumes);
2890 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2891 if (light->flags & flag)
2892 R_DrawRTLight(&light->rtlight, visiblevolumes);
2894 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2895 R_DrawRTLight(&light->rtlight, visiblevolumes);
2899 qglEnable(GL_CULL_FACE);
2900 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2903 R_Shadow_Stage_End();
2906 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2907 typedef struct suffixinfo_s
2910 qboolean flipx, flipy, flipdiagonal;
2913 static suffixinfo_t suffix[3][6] =
2916 {"px", false, false, false},
2917 {"nx", false, false, false},
2918 {"py", false, false, false},
2919 {"ny", false, false, false},
2920 {"pz", false, false, false},
2921 {"nz", false, false, false}
2924 {"posx", false, false, false},
2925 {"negx", false, false, false},
2926 {"posy", false, false, false},
2927 {"negy", false, false, false},
2928 {"posz", false, false, false},
2929 {"negz", false, false, false}
2932 {"rt", true, false, true},
2933 {"lf", false, true, true},
2934 {"ft", true, true, false},
2935 {"bk", false, false, false},
2936 {"up", true, false, true},
2937 {"dn", true, false, true}
2941 static int componentorder[4] = {0, 1, 2, 3};
2943 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2945 int i, j, cubemapsize;
2946 qbyte *cubemappixels, *image_rgba;
2947 rtexture_t *cubemaptexture;
2949 // must start 0 so the first loadimagepixels has no requested width/height
2951 cubemappixels = NULL;
2952 cubemaptexture = NULL;
2953 // keep trying different suffix groups (posx, px, rt) until one loads
2954 for (j = 0;j < 3 && !cubemappixels;j++)
2956 // load the 6 images in the suffix group
2957 for (i = 0;i < 6;i++)
2959 // generate an image name based on the base and and suffix
2960 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2962 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2964 // an image loaded, make sure width and height are equal
2965 if (image_width == image_height)
2967 // if this is the first image to load successfully, allocate the cubemap memory
2968 if (!cubemappixels && image_width >= 1)
2970 cubemapsize = image_width;
2971 // note this clears to black, so unavailable sides are black
2972 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2974 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2976 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);
2979 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2981 Mem_Free(image_rgba);
2985 // if a cubemap loaded, upload it
2988 if (!r_shadow_filters_texturepool)
2989 r_shadow_filters_texturepool = R_AllocTexturePool();
2990 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2991 Mem_Free(cubemappixels);
2995 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2996 for (j = 0;j < 3;j++)
2997 for (i = 0;i < 6;i++)
2998 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2999 Con_Print(" and was unable to find any of them.\n");
3001 return cubemaptexture;
3004 rtexture_t *R_Shadow_Cubemap(const char *basename)
3007 for (i = 0;i < numcubemaps;i++)
3008 if (!strcasecmp(cubemaps[i].basename, basename))
3009 return cubemaps[i].texture;
3010 if (i >= MAX_CUBEMAPS)
3013 strcpy(cubemaps[i].basename, basename);
3014 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3015 return cubemaps[i].texture;
3018 void R_Shadow_FreeCubemaps(void)
3021 R_FreeTexturePool(&r_shadow_filters_texturepool);
3024 dlight_t *R_Shadow_NewWorldLight(void)
3027 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3028 light->next = r_shadow_worldlightchain;
3029 r_shadow_worldlightchain = light;
3033 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)
3035 VectorCopy(origin, light->origin);
3036 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3037 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3038 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3039 light->color[0] = max(color[0], 0);
3040 light->color[1] = max(color[1], 0);
3041 light->color[2] = max(color[2], 0);
3042 light->radius = max(radius, 0);
3043 light->style = style;
3044 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3046 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3049 light->shadow = shadowenable;
3050 light->corona = corona;
3053 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3054 light->coronasizescale = coronasizescale;
3055 light->ambientscale = ambientscale;
3056 light->diffusescale = diffusescale;
3057 light->specularscale = specularscale;
3058 light->flags = flags;
3059 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3061 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3064 void R_Shadow_FreeWorldLight(dlight_t *light)
3066 dlight_t **lightpointer;
3067 R_RTLight_Uncompile(&light->rtlight);
3068 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3069 if (*lightpointer != light)
3070 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3071 *lightpointer = light->next;
3075 void R_Shadow_ClearWorldLights(void)
3077 while (r_shadow_worldlightchain)
3078 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3079 r_shadow_selectedlight = NULL;
3080 R_Shadow_FreeCubemaps();
3083 void R_Shadow_SelectLight(dlight_t *light)
3085 if (r_shadow_selectedlight)
3086 r_shadow_selectedlight->selected = false;
3087 r_shadow_selectedlight = light;
3088 if (r_shadow_selectedlight)
3089 r_shadow_selectedlight->selected = true;
3092 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3094 float scale = r_editlights_cursorgrid.value * 0.5f;
3095 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);
3098 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3101 const dlight_t *light;
3104 if (light->selected)
3105 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3108 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);
3111 void R_Shadow_DrawLightSprites(void)
3117 for (i = 0;i < 5;i++)
3119 lighttextures[i] = NULL;
3120 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3121 lighttextures[i] = pic->tex;
3124 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3125 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3126 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3129 void R_Shadow_SelectLightInView(void)
3131 float bestrating, rating, temp[3];
3132 dlight_t *best, *light;
3135 for (light = r_shadow_worldlightchain;light;light = light->next)
3137 VectorSubtract(light->origin, r_vieworigin, temp);
3138 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3141 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3142 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3144 bestrating = rating;
3149 R_Shadow_SelectLight(best);
3152 void R_Shadow_LoadWorldLights(void)
3154 int n, a, style, shadow, flags;
3155 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3156 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3157 if (r_refdef.worldmodel == NULL)
3159 Con_Print("No map loaded.\n");
3162 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3163 strlcat (name, ".rtlights", sizeof (name));
3164 lightsstring = FS_LoadFile(name, tempmempool, false);
3174 for (;COM_Parse(t, true) && strcmp(
3175 if (COM_Parse(t, true))
3177 if (com_token[0] == '!')
3180 origin[0] = atof(com_token+1);
3183 origin[0] = atof(com_token);
3188 while (*s && *s != '\n' && *s != '\r')
3194 // check for modifier flags
3201 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);
3204 flags = LIGHTFLAG_REALTIMEMODE;
3212 coronasizescale = 0.25f;
3214 VectorClear(angles);
3217 if (a < 9 || !strcmp(cubemapname, "\"\""))
3219 // remove quotes on cubemapname
3220 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3222 cubemapname[strlen(cubemapname)-1] = 0;
3223 strcpy(cubemapname, cubemapname + 1);
3227 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);
3230 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3231 radius *= r_editlights_rtlightssizescale.value;
3232 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3240 Con_Printf("invalid rtlights file \"%s\"\n", name);
3241 Mem_Free(lightsstring);
3245 void R_Shadow_SaveWorldLights(void)
3248 int bufchars, bufmaxchars;
3250 char name[MAX_QPATH];
3252 if (!r_shadow_worldlightchain)
3254 if (r_refdef.worldmodel == NULL)
3256 Con_Print("No map loaded.\n");
3259 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3260 strlcat (name, ".rtlights", sizeof (name));
3261 bufchars = bufmaxchars = 0;
3263 for (light = r_shadow_worldlightchain;light;light = light->next)
3265 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3266 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);
3267 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3268 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]);
3270 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);
3271 if (bufchars + (int) strlen(line) > bufmaxchars)
3273 bufmaxchars = bufchars + strlen(line) + 2048;
3275 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3279 memcpy(buf, oldbuf, bufchars);
3285 memcpy(buf + bufchars, line, strlen(line));
3286 bufchars += strlen(line);
3290 FS_WriteFile(name, buf, bufchars);
3295 void R_Shadow_LoadLightsFile(void)
3298 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3299 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3300 if (r_refdef.worldmodel == NULL)
3302 Con_Print("No map loaded.\n");
3305 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3306 strlcat (name, ".lights", sizeof (name));
3307 lightsstring = FS_LoadFile(name, tempmempool, false);
3315 while (*s && *s != '\n' && *s != '\r')
3321 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);
3325 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);
3328 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3329 radius = bound(15, radius, 4096);
3330 VectorScale(color, (2.0f / (8388608.0f)), color);
3331 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3339 Con_Printf("invalid lights file \"%s\"\n", name);
3340 Mem_Free(lightsstring);
3344 // tyrlite/hmap2 light types in the delay field
3345 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3347 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3349 int entnum, style, islight, skin, pflags, effects, type, n;
3352 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3353 char key[256], value[1024];
3355 if (r_refdef.worldmodel == NULL)
3357 Con_Print("No map loaded.\n");
3360 // try to load a .ent file first
3361 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3362 strlcat (key, ".ent", sizeof (key));
3363 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3364 // and if that is not found, fall back to the bsp file entity string
3366 data = r_refdef.worldmodel->brush.entities;
3369 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3371 type = LIGHTTYPE_MINUSX;
3372 origin[0] = origin[1] = origin[2] = 0;
3373 originhack[0] = originhack[1] = originhack[2] = 0;
3374 angles[0] = angles[1] = angles[2] = 0;
3375 color[0] = color[1] = color[2] = 1;
3376 light[0] = light[1] = light[2] = 1;light[3] = 300;
3377 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3387 if (!COM_ParseToken(&data, false))
3389 if (com_token[0] == '}')
3390 break; // end of entity
3391 if (com_token[0] == '_')
3392 strcpy(key, com_token + 1);
3394 strcpy(key, com_token);
3395 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3396 key[strlen(key)-1] = 0;
3397 if (!COM_ParseToken(&data, false))
3399 strcpy(value, com_token);
3401 // now that we have the key pair worked out...
3402 if (!strcmp("light", key))
3404 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3408 light[0] = vec[0] * (1.0f / 256.0f);
3409 light[1] = vec[0] * (1.0f / 256.0f);
3410 light[2] = vec[0] * (1.0f / 256.0f);
3416 light[0] = vec[0] * (1.0f / 255.0f);
3417 light[1] = vec[1] * (1.0f / 255.0f);
3418 light[2] = vec[2] * (1.0f / 255.0f);
3422 else if (!strcmp("delay", key))
3424 else if (!strcmp("origin", key))
3425 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3426 else if (!strcmp("angle", key))
3427 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3428 else if (!strcmp("angles", key))
3429 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3430 else if (!strcmp("color", key))
3431 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3432 else if (!strcmp("wait", key))
3433 fadescale = atof(value);
3434 else if (!strcmp("classname", key))
3436 if (!strncmp(value, "light", 5))
3439 if (!strcmp(value, "light_fluoro"))
3444 overridecolor[0] = 1;
3445 overridecolor[1] = 1;
3446 overridecolor[2] = 1;
3448 if (!strcmp(value, "light_fluorospark"))
3453 overridecolor[0] = 1;
3454 overridecolor[1] = 1;
3455 overridecolor[2] = 1;
3457 if (!strcmp(value, "light_globe"))
3462 overridecolor[0] = 1;
3463 overridecolor[1] = 0.8;
3464 overridecolor[2] = 0.4;
3466 if (!strcmp(value, "light_flame_large_yellow"))
3471 overridecolor[0] = 1;
3472 overridecolor[1] = 0.5;
3473 overridecolor[2] = 0.1;
3475 if (!strcmp(value, "light_flame_small_yellow"))
3480 overridecolor[0] = 1;
3481 overridecolor[1] = 0.5;
3482 overridecolor[2] = 0.1;
3484 if (!strcmp(value, "light_torch_small_white"))
3489 overridecolor[0] = 1;
3490 overridecolor[1] = 0.5;
3491 overridecolor[2] = 0.1;
3493 if (!strcmp(value, "light_torch_small_walltorch"))
3498 overridecolor[0] = 1;
3499 overridecolor[1] = 0.5;
3500 overridecolor[2] = 0.1;
3504 else if (!strcmp("style", key))
3505 style = atoi(value);
3506 else if (r_refdef.worldmodel->type == mod_brushq3)
3508 if (!strcmp("scale", key))
3509 lightscale = atof(value);
3510 if (!strcmp("fade", key))
3511 fadescale = atof(value);
3513 else if (!strcmp("skin", key))
3514 skin = (int)atof(value);
3515 else if (!strcmp("pflags", key))
3516 pflags = (int)atof(value);
3517 else if (!strcmp("effects", key))
3518 effects = (int)atof(value);
3522 if (lightscale <= 0)
3526 if (color[0] == color[1] && color[0] == color[2])
3528 color[0] *= overridecolor[0];
3529 color[1] *= overridecolor[1];
3530 color[2] *= overridecolor[2];
3532 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3533 color[0] = color[0] * light[0];
3534 color[1] = color[1] * light[1];
3535 color[2] = color[2] * light[2];
3538 case LIGHTTYPE_MINUSX:
3540 case LIGHTTYPE_RECIPX:
3542 VectorScale(color, (1.0f / 16.0f), color);
3544 case LIGHTTYPE_RECIPXX:
3546 VectorScale(color, (1.0f / 16.0f), color);
3549 case LIGHTTYPE_NONE:
3553 case LIGHTTYPE_MINUSXX:
3556 VectorAdd(origin, originhack, origin);
3558 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);
3561 Mem_Free(entfiledata);
3565 void R_Shadow_SetCursorLocationForView(void)
3567 vec_t dist, push, frac;
3568 vec3_t dest, endpos, normal;
3569 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3570 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3573 dist = frac * r_editlights_cursordistance.value;
3574 push = r_editlights_cursorpushback.value;
3578 VectorMA(endpos, push, r_viewforward, endpos);
3579 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3581 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3582 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3583 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3586 void R_Shadow_UpdateWorldLightSelection(void)
3588 if (r_editlights.integer)
3590 R_Shadow_SetCursorLocationForView();
3591 R_Shadow_SelectLightInView();
3592 R_Shadow_DrawLightSprites();
3595 R_Shadow_SelectLight(NULL);
3598 void R_Shadow_EditLights_Clear_f(void)
3600 R_Shadow_ClearWorldLights();
3603 void R_Shadow_EditLights_Reload_f(void)
3605 if (!r_refdef.worldmodel)
3607 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3608 R_Shadow_ClearWorldLights();
3609 R_Shadow_LoadWorldLights();
3610 if (r_shadow_worldlightchain == NULL)
3612 R_Shadow_LoadLightsFile();
3613 if (r_shadow_worldlightchain == NULL)
3614 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3618 void R_Shadow_EditLights_Save_f(void)
3620 if (!r_refdef.worldmodel)
3622 R_Shadow_SaveWorldLights();
3625 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3627 R_Shadow_ClearWorldLights();
3628 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3631 void R_Shadow_EditLights_ImportLightsFile_f(void)
3633 R_Shadow_ClearWorldLights();
3634 R_Shadow_LoadLightsFile();
3637 void R_Shadow_EditLights_Spawn_f(void)
3640 if (!r_editlights.integer)
3642 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3645 if (Cmd_Argc() != 1)
3647 Con_Print("r_editlights_spawn does not take parameters\n");
3650 color[0] = color[1] = color[2] = 1;
3651 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3654 void R_Shadow_EditLights_Edit_f(void)
3656 vec3_t origin, angles, color;
3657 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3658 int style, shadows, flags, normalmode, realtimemode;
3659 char cubemapname[1024];
3660 if (!r_editlights.integer)
3662 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3665 if (!r_shadow_selectedlight)
3667 Con_Print("No selected light.\n");
3670 VectorCopy(r_shadow_selectedlight->origin, origin);
3671 VectorCopy(r_shadow_selectedlight->angles, angles);
3672 VectorCopy(r_shadow_selectedlight->color, color);
3673 radius = r_shadow_selectedlight->radius;
3674 style = r_shadow_selectedlight->style;
3675 if (r_shadow_selectedlight->cubemapname)
3676 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3679 shadows = r_shadow_selectedlight->shadow;
3680 corona = r_shadow_selectedlight->corona;
3681 coronasizescale = r_shadow_selectedlight->coronasizescale;
3682 ambientscale = r_shadow_selectedlight->ambientscale;
3683 diffusescale = r_shadow_selectedlight->diffusescale;
3684 specularscale = r_shadow_selectedlight->specularscale;
3685 flags = r_shadow_selectedlight->flags;
3686 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3687 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3688 if (!strcmp(Cmd_Argv(1), "origin"))
3690 if (Cmd_Argc() != 5)
3692 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3695 origin[0] = atof(Cmd_Argv(2));
3696 origin[1] = atof(Cmd_Argv(3));
3697 origin[2] = atof(Cmd_Argv(4));
3699 else if (!strcmp(Cmd_Argv(1), "originx"))
3701 if (Cmd_Argc() != 3)
3703 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3706 origin[0] = atof(Cmd_Argv(2));
3708 else if (!strcmp(Cmd_Argv(1), "originy"))
3710 if (Cmd_Argc() != 3)
3712 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3715 origin[1] = atof(Cmd_Argv(2));
3717 else if (!strcmp(Cmd_Argv(1), "originz"))
3719 if (Cmd_Argc() != 3)
3721 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3724 origin[2] = atof(Cmd_Argv(2));
3726 else if (!strcmp(Cmd_Argv(1), "move"))
3728 if (Cmd_Argc() != 5)
3730 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3733 origin[0] += atof(Cmd_Argv(2));
3734 origin[1] += atof(Cmd_Argv(3));
3735 origin[2] += atof(Cmd_Argv(4));
3737 else if (!strcmp(Cmd_Argv(1), "movex"))
3739 if (Cmd_Argc() != 3)
3741 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3744 origin[0] += atof(Cmd_Argv(2));
3746 else if (!strcmp(Cmd_Argv(1), "movey"))
3748 if (Cmd_Argc() != 3)
3750 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3753 origin[1] += atof(Cmd_Argv(2));
3755 else if (!strcmp(Cmd_Argv(1), "movez"))
3757 if (Cmd_Argc() != 3)
3759 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3762 origin[2] += atof(Cmd_Argv(2));
3764 else if (!strcmp(Cmd_Argv(1), "angles"))
3766 if (Cmd_Argc() != 5)
3768 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3771 angles[0] = atof(Cmd_Argv(2));
3772 angles[1] = atof(Cmd_Argv(3));
3773 angles[2] = atof(Cmd_Argv(4));
3775 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3777 if (Cmd_Argc() != 3)
3779 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3782 angles[0] = atof(Cmd_Argv(2));
3784 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3786 if (Cmd_Argc() != 3)
3788 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3791 angles[1] = atof(Cmd_Argv(2));
3793 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3795 if (Cmd_Argc() != 3)
3797 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3800 angles[2] = atof(Cmd_Argv(2));
3802 else if (!strcmp(Cmd_Argv(1), "color"))
3804 if (Cmd_Argc() != 5)
3806 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3809 color[0] = atof(Cmd_Argv(2));
3810 color[1] = atof(Cmd_Argv(3));
3811 color[2] = atof(Cmd_Argv(4));
3813 else if (!strcmp(Cmd_Argv(1), "radius"))
3815 if (Cmd_Argc() != 3)
3817 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3820 radius = atof(Cmd_Argv(2));
3822 else if (!strcmp(Cmd_Argv(1), "style"))
3824 if (Cmd_Argc() != 3)
3826 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3829 style = atoi(Cmd_Argv(2));
3831 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3835 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3838 if (Cmd_Argc() == 3)
3839 strcpy(cubemapname, Cmd_Argv(2));
3843 else if (!strcmp(Cmd_Argv(1), "shadows"))
3845 if (Cmd_Argc() != 3)
3847 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3850 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3852 else if (!strcmp(Cmd_Argv(1), "corona"))
3854 if (Cmd_Argc() != 3)
3856 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3859 corona = atof(Cmd_Argv(2));
3861 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3863 if (Cmd_Argc() != 3)
3865 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3868 coronasizescale = atof(Cmd_Argv(2));
3870 else if (!strcmp(Cmd_Argv(1), "ambient"))
3872 if (Cmd_Argc() != 3)
3874 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3877 ambientscale = atof(Cmd_Argv(2));
3879 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3881 if (Cmd_Argc() != 3)
3883 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3886 diffusescale = atof(Cmd_Argv(2));
3888 else if (!strcmp(Cmd_Argv(1), "specular"))
3890 if (Cmd_Argc() != 3)
3892 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3895 specularscale = atof(Cmd_Argv(2));
3897 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3899 if (Cmd_Argc() != 3)
3901 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3904 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3906 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3908 if (Cmd_Argc() != 3)
3910 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3913 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3917 Con_Print("usage: r_editlights_edit [property] [value]\n");
3918 Con_Print("Selected light's properties:\n");
3919 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3920 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3921 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3922 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3923 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3924 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3925 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3926 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3927 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3928 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3929 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3930 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3931 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3932 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3935 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3936 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3939 void R_Shadow_EditLights_EditAll_f(void)
3943 if (!r_editlights.integer)
3945 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3949 for (light = r_shadow_worldlightchain;light;light = light->next)
3951 R_Shadow_SelectLight(light);
3952 R_Shadow_EditLights_Edit_f();
3956 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3958 int lightnumber, lightcount;
3962 if (!r_editlights.integer)
3968 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3969 if (light == r_shadow_selectedlight)
3970 lightnumber = lightcount;
3971 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;
3972 if (r_shadow_selectedlight == NULL)
3974 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3975 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;
3976 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;
3977 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;
3978 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3979 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3980 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3981 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;
3982 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3983 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3984 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3985 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3986 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3987 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;
3988 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;
3991 void R_Shadow_EditLights_ToggleShadow_f(void)
3993 if (!r_editlights.integer)
3995 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3998 if (!r_shadow_selectedlight)
4000 Con_Print("No selected light.\n");
4003 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);
4006 void R_Shadow_EditLights_ToggleCorona_f(void)
4008 if (!r_editlights.integer)
4010 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4013 if (!r_shadow_selectedlight)
4015 Con_Print("No selected light.\n");
4018 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);
4021 void R_Shadow_EditLights_Remove_f(void)
4023 if (!r_editlights.integer)
4025 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4028 if (!r_shadow_selectedlight)
4030 Con_Print("No selected light.\n");
4033 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4034 r_shadow_selectedlight = NULL;
4037 void R_Shadow_EditLights_Help_f(void)
4040 "Documentation on r_editlights system:\n"
4042 "r_editlights : enable/disable editing mode\n"
4043 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4044 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4045 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4046 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4047 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4048 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4049 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4051 "r_editlights_help : this help\n"
4052 "r_editlights_clear : remove all lights\n"
4053 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4054 "r_editlights_save : save to .rtlights file\n"
4055 "r_editlights_spawn : create a light with default settings\n"
4056 "r_editlights_edit command : edit selected light - more documentation below\n"
4057 "r_editlights_remove : remove selected light\n"
4058 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4059 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4060 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4062 "origin x y z : set light location\n"
4063 "originx x: set x component of light location\n"
4064 "originy y: set y component of light location\n"
4065 "originz z: set z component of light location\n"
4066 "move x y z : adjust light location\n"
4067 "movex x: adjust x component of light location\n"
4068 "movey y: adjust y component of light location\n"
4069 "movez z: adjust z component of light location\n"
4070 "angles x y z : set light angles\n"
4071 "anglesx x: set x component of light angles\n"
4072 "anglesy y: set y component of light angles\n"
4073 "anglesz z: set z component of light angles\n"
4074 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4075 "radius radius : set radius (size) of light\n"
4076 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4077 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4078 "shadows 1/0 : turn on/off shadows\n"
4079 "corona n : set corona intensity\n"
4080 "coronasize n : set corona size (0-1)\n"
4081 "ambient n : set ambient intensity (0-1)\n"
4082 "diffuse n : set diffuse intensity (0-1)\n"
4083 "specular n : set specular intensity (0-1)\n"
4084 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4085 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4086 "<nothing> : print light properties to console\n"
4090 void R_Shadow_EditLights_CopyInfo_f(void)
4092 if (!r_editlights.integer)
4094 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4097 if (!r_shadow_selectedlight)
4099 Con_Print("No selected light.\n");
4102 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4103 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4104 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4105 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4106 if (r_shadow_selectedlight->cubemapname)
4107 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4109 r_shadow_bufferlight.cubemapname[0] = 0;
4110 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4111 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4112 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4113 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4114 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4115 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4116 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4119 void R_Shadow_EditLights_PasteInfo_f(void)
4121 if (!r_editlights.integer)
4123 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4126 if (!r_shadow_selectedlight)
4128 Con_Print("No selected light.\n");
4131 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);
4134 void R_Shadow_EditLights_Init(void)
4136 Cvar_RegisterVariable(&r_editlights);
4137 Cvar_RegisterVariable(&r_editlights_cursordistance);
4138 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4139 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4140 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4141 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4142 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4143 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4144 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4145 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4146 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4147 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4148 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4149 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4150 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4151 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4152 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4153 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4154 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4155 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4156 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4157 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);