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.02"};
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 = clamp(1.0 - dot(CubeVector, CubeVector), 0.0, 1.0);\n"
353 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
356 "#ifdef USEOFFSETMAPPING\n"
357 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-1, 1);\n"
358 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
359 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
360 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
361 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
364 "#ifdef USECUBEFILTER\n"
365 " // apply light cubemap filter\n"
366 " LightColor *= vec3(textureCube(Texture_Cube, CubeVector));\n"
369 " // get the texels - with a blendmap we'd need to blend multiple here\n"
370 " vec3 surfacenormal = vec3(texture2D(Texture_Normal, TexCoord)) * 2.0 - 1.0;\n"
371 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
372 "#ifdef USESPECULAR\n"
373 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
376 " // calculate shading\n"
377 " vec3 diffusenormal = normalize(LightVector);\n"
378 " vec3 color = colortexel * (AmbientScale + DiffuseScale * clamp(dot(surfacenormal, diffusenormal), 0.0, 1.0));\n"
379 "#ifdef USESPECULAR\n"
380 " color += glosstexel * (SpecularScale * pow(clamp(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0, 1.0), SpecularPower));\n"
383 " // calculate fragment color\n"
384 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
388 void r_shadow_start(void)
391 // allocate vertex processing arrays
393 r_shadow_normalcubetexture = NULL;
394 r_shadow_attenuation2dtexture = NULL;
395 r_shadow_attenuation3dtexture = NULL;
396 r_shadow_blankbumptexture = NULL;
397 r_shadow_blankglosstexture = NULL;
398 r_shadow_blankwhitetexture = NULL;
399 r_shadow_blankwhitecubetexture = NULL;
400 r_shadow_blankblacktexture = NULL;
401 r_shadow_texturepool = NULL;
402 r_shadow_filters_texturepool = NULL;
403 R_Shadow_ValidateCvars();
404 R_Shadow_MakeTextures();
405 maxshadowelements = 0;
406 shadowelements = NULL;
414 shadowmarklist = NULL;
416 r_shadow_buffer_numclusterpvsbytes = 0;
417 r_shadow_buffer_clusterpvs = NULL;
418 r_shadow_buffer_clusterlist = NULL;
419 r_shadow_buffer_numsurfacepvsbytes = 0;
420 r_shadow_buffer_surfacepvs = NULL;
421 r_shadow_buffer_surfacelist = NULL;
422 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
423 r_shadow_program_light[i] = 0;
424 if (gl_support_fragment_shader)
426 char *vertstring, *fragstring;
427 int vertstrings_count;
428 int fragstrings_count;
429 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
430 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
431 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
432 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
433 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
435 vertstrings_count = 0;
436 fragstrings_count = 0;
437 if (i & SHADERPERMUTATION_SPECULAR)
439 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
440 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
442 if (i & SHADERPERMUTATION_FOG)
444 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
445 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
447 if (i & SHADERPERMUTATION_CUBEFILTER)
449 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
450 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
452 if (i & SHADERPERMUTATION_OFFSETMAPPING)
454 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
455 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
457 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
458 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
459 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
460 qglUseProgramObjectARB(r_shadow_program_light[i]);
461 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
462 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
463 if (i & SHADERPERMUTATION_SPECULAR)
465 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
467 if (i & SHADERPERMUTATION_CUBEFILTER)
469 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
471 if (i & SHADERPERMUTATION_FOG)
473 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
476 qglUseProgramObjectARB(0);
478 Mem_Free(fragstring);
480 Mem_Free(vertstring);
484 void r_shadow_shutdown(void)
487 R_Shadow_UncompileWorldLights();
488 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
490 if (r_shadow_program_light[i])
492 GL_Backend_FreeProgram(r_shadow_program_light[i]);
493 r_shadow_program_light[i] = 0;
497 r_shadow_normalcubetexture = NULL;
498 r_shadow_attenuation2dtexture = NULL;
499 r_shadow_attenuation3dtexture = NULL;
500 r_shadow_blankbumptexture = NULL;
501 r_shadow_blankglosstexture = NULL;
502 r_shadow_blankwhitetexture = NULL;
503 r_shadow_blankwhitecubetexture = NULL;
504 r_shadow_blankblacktexture = NULL;
505 R_FreeTexturePool(&r_shadow_texturepool);
506 R_FreeTexturePool(&r_shadow_filters_texturepool);
507 maxshadowelements = 0;
509 Mem_Free(shadowelements);
510 shadowelements = NULL;
513 Mem_Free(vertexupdate);
516 Mem_Free(vertexremap);
522 Mem_Free(shadowmark);
525 Mem_Free(shadowmarklist);
526 shadowmarklist = NULL;
528 r_shadow_buffer_numclusterpvsbytes = 0;
529 if (r_shadow_buffer_clusterpvs)
530 Mem_Free(r_shadow_buffer_clusterpvs);
531 r_shadow_buffer_clusterpvs = NULL;
532 if (r_shadow_buffer_clusterlist)
533 Mem_Free(r_shadow_buffer_clusterlist);
534 r_shadow_buffer_clusterlist = NULL;
535 r_shadow_buffer_numsurfacepvsbytes = 0;
536 if (r_shadow_buffer_surfacepvs)
537 Mem_Free(r_shadow_buffer_surfacepvs);
538 r_shadow_buffer_surfacepvs = NULL;
539 if (r_shadow_buffer_surfacelist)
540 Mem_Free(r_shadow_buffer_surfacelist);
541 r_shadow_buffer_surfacelist = NULL;
544 void r_shadow_newmap(void)
548 void R_Shadow_Help_f(void)
551 "Documentation on r_shadow system:\n"
553 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
554 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
555 "r_shadow_debuglight : render only this light number (-1 = all)\n"
556 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
557 "r_shadow_gloss2intensity : brightness of forced gloss\n"
558 "r_shadow_glossintensity : brightness of textured gloss\n"
559 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
560 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
561 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
562 "r_shadow_portallight : use portal visibility for static light precomputation\n"
563 "r_shadow_projectdistance : shadow volume projection distance\n"
564 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
565 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
566 "r_shadow_realtime_world : use high quality world lighting mode\n"
567 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
568 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
569 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
570 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
571 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
572 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
573 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
574 "r_shadow_scissor : use scissor optimization\n"
575 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
576 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
577 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
578 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
579 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
581 "r_shadow_help : this help\n"
585 void R_Shadow_Init(void)
587 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
588 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
589 Cvar_RegisterVariable(&r_shadow_cull);
590 Cvar_RegisterVariable(&r_shadow_debuglight);
591 Cvar_RegisterVariable(&r_shadow_gloss);
592 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
593 Cvar_RegisterVariable(&r_shadow_glossintensity);
594 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
595 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
596 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
597 Cvar_RegisterVariable(&r_shadow_portallight);
598 Cvar_RegisterVariable(&r_shadow_projectdistance);
599 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
600 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
601 Cvar_RegisterVariable(&r_shadow_realtime_world);
602 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
603 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
604 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
605 Cvar_RegisterVariable(&r_shadow_scissor);
606 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
607 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
608 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
609 Cvar_RegisterVariable(&r_shadow_staticworldlights);
610 Cvar_RegisterVariable(&r_shadow_texture3d);
611 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
612 Cvar_RegisterVariable(&r_shadow_glsl);
613 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
614 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
615 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
616 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
617 if (gamemode == GAME_TENEBRAE)
619 Cvar_SetValue("r_shadow_gloss", 2);
620 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
622 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
623 R_Shadow_EditLights_Init();
624 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
625 r_shadow_worldlightchain = NULL;
626 maxshadowelements = 0;
627 shadowelements = NULL;
635 shadowmarklist = NULL;
637 r_shadow_buffer_numclusterpvsbytes = 0;
638 r_shadow_buffer_clusterpvs = NULL;
639 r_shadow_buffer_clusterlist = NULL;
640 r_shadow_buffer_numsurfacepvsbytes = 0;
641 r_shadow_buffer_surfacepvs = NULL;
642 r_shadow_buffer_surfacelist = NULL;
643 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
646 matrix4x4_t matrix_attenuationxyz =
649 {0.5, 0.0, 0.0, 0.5},
650 {0.0, 0.5, 0.0, 0.5},
651 {0.0, 0.0, 0.5, 0.5},
656 matrix4x4_t matrix_attenuationz =
659 {0.0, 0.0, 0.5, 0.5},
660 {0.0, 0.0, 0.0, 0.5},
661 {0.0, 0.0, 0.0, 0.5},
666 int *R_Shadow_ResizeShadowElements(int numtris)
668 // make sure shadowelements is big enough for this volume
669 if (maxshadowelements < numtris * 24)
671 maxshadowelements = numtris * 24;
673 Mem_Free(shadowelements);
674 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
676 return shadowelements;
679 void R_Shadow_EnlargeClusterBuffer(int numclusters)
681 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
682 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
684 if (r_shadow_buffer_clusterpvs)
685 Mem_Free(r_shadow_buffer_clusterpvs);
686 if (r_shadow_buffer_clusterlist)
687 Mem_Free(r_shadow_buffer_clusterlist);
688 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
689 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
690 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
694 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
696 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
697 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
699 if (r_shadow_buffer_surfacepvs)
700 Mem_Free(r_shadow_buffer_surfacepvs);
701 if (r_shadow_buffer_surfacelist)
702 Mem_Free(r_shadow_buffer_surfacelist);
703 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
704 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
705 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
709 void R_Shadow_PrepareShadowMark(int numtris)
711 // make sure shadowmark is big enough for this volume
712 if (maxshadowmark < numtris)
714 maxshadowmark = numtris;
716 Mem_Free(shadowmark);
718 Mem_Free(shadowmarklist);
719 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
720 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
724 // if shadowmarkcount wrapped we clear the array and adjust accordingly
725 if (shadowmarkcount == 0)
728 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
733 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)
735 int i, j, tris = 0, vr[3], t, outvertices = 0;
740 if (maxvertexupdate < innumvertices)
742 maxvertexupdate = innumvertices;
744 Mem_Free(vertexupdate);
746 Mem_Free(vertexremap);
747 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
748 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
752 if (vertexupdatenum == 0)
755 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
756 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
759 for (i = 0;i < numshadowmarktris;i++)
760 shadowmark[shadowmarktris[i]] = shadowmarkcount;
762 for (i = 0;i < numshadowmarktris;i++)
764 t = shadowmarktris[i];
765 e = inelement3i + t * 3;
766 // make sure the vertices are created
767 for (j = 0;j < 3;j++)
769 if (vertexupdate[e[j]] != vertexupdatenum)
771 vertexupdate[e[j]] = vertexupdatenum;
772 vertexremap[e[j]] = outvertices;
773 v = invertex3f + e[j] * 3;
774 // project one copy of the vertex to the sphere radius of the light
775 // (FIXME: would projecting it to the light box be better?)
776 VectorSubtract(v, projectorigin, temp);
777 f = projectdistance / VectorLength(temp);
778 VectorCopy(v, outvertex3f);
779 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
786 for (i = 0;i < numshadowmarktris;i++)
788 t = shadowmarktris[i];
789 e = inelement3i + t * 3;
790 n = inneighbor3i + t * 3;
791 // output the front and back triangles
792 outelement3i[0] = vertexremap[e[0]];
793 outelement3i[1] = vertexremap[e[1]];
794 outelement3i[2] = vertexremap[e[2]];
795 outelement3i[3] = vertexremap[e[2]] + 1;
796 outelement3i[4] = vertexremap[e[1]] + 1;
797 outelement3i[5] = vertexremap[e[0]] + 1;
800 // output the sides (facing outward from this triangle)
801 if (shadowmark[n[0]] != shadowmarkcount)
803 vr[0] = vertexremap[e[0]];
804 vr[1] = vertexremap[e[1]];
805 outelement3i[0] = vr[1];
806 outelement3i[1] = vr[0];
807 outelement3i[2] = vr[0] + 1;
808 outelement3i[3] = vr[1];
809 outelement3i[4] = vr[0] + 1;
810 outelement3i[5] = vr[1] + 1;
814 if (shadowmark[n[1]] != shadowmarkcount)
816 vr[1] = vertexremap[e[1]];
817 vr[2] = vertexremap[e[2]];
818 outelement3i[0] = vr[2];
819 outelement3i[1] = vr[1];
820 outelement3i[2] = vr[1] + 1;
821 outelement3i[3] = vr[2];
822 outelement3i[4] = vr[1] + 1;
823 outelement3i[5] = vr[2] + 1;
827 if (shadowmark[n[2]] != shadowmarkcount)
829 vr[0] = vertexremap[e[0]];
830 vr[2] = vertexremap[e[2]];
831 outelement3i[0] = vr[0];
832 outelement3i[1] = vr[2];
833 outelement3i[2] = vr[2] + 1;
834 outelement3i[3] = vr[0];
835 outelement3i[4] = vr[2] + 1;
836 outelement3i[5] = vr[0] + 1;
842 *outnumvertices = outvertices;
846 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)
849 if (projectdistance < 0.1)
851 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
854 if (!numverts || !nummarktris)
856 // make sure shadowelements is big enough for this volume
857 if (maxshadowelements < nummarktris * 24)
858 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
859 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
860 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
863 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs)
868 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
870 tend = firsttriangle + numtris;
871 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
872 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
873 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
875 // surface box entirely inside light box, no box cull
876 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
877 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
878 shadowmarklist[numshadowmark++] = t;
882 // surface box not entirely inside light box, cull each triangle
883 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
885 v[0] = invertex3f + e[0] * 3;
886 v[1] = invertex3f + e[1] * 3;
887 v[2] = invertex3f + e[2] * 3;
888 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
889 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
890 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
891 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
892 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
893 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
894 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
895 shadowmarklist[numshadowmark++] = t;
900 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
903 if (r_shadow_compilingrtlight)
905 // if we're compiling an rtlight, capture the mesh
906 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
909 memset(&m, 0, sizeof(m));
910 m.pointer_vertex = vertex3f;
912 GL_LockArrays(0, numvertices);
913 if (r_shadowstage == SHADOWSTAGE_STENCIL)
915 // increment stencil if backface is behind depthbuffer
916 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
917 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
918 R_Mesh_Draw(numvertices, numtriangles, element3i);
920 c_rt_shadowtris += numtriangles;
921 // decrement stencil if frontface is behind depthbuffer
922 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
923 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
925 R_Mesh_Draw(numvertices, numtriangles, element3i);
927 c_rt_shadowtris += numtriangles;
931 static void R_Shadow_MakeTextures(void)
933 int x, y, z, d, side;
934 float v[3], s, t, intensity;
936 R_FreeTexturePool(&r_shadow_texturepool);
937 r_shadow_texturepool = R_AllocTexturePool();
938 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
939 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
941 #define ATTEN2DSIZE 64
942 #define ATTEN3DSIZE 32
943 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
944 data[0] = 128; // normal X
945 data[1] = 128; // normal Y
946 data[2] = 255; // normal Z
947 data[3] = 128; // height
948 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
953 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
958 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
963 r_shadow_blankblacktexture = R_LoadTexture2D(r_shadow_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
964 r_shadow_blankwhitecubetexture = NULL;
965 r_shadow_normalcubetexture = NULL;
966 if (gl_texturecubemap)
968 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
969 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
970 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
971 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
972 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
973 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
974 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
975 for (side = 0;side < 6;side++)
977 for (y = 0;y < NORMSIZE;y++)
979 for (x = 0;x < NORMSIZE;x++)
981 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
982 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1016 intensity = 127.0f / sqrt(DotProduct(v, v));
1017 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1018 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1019 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1020 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1024 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1026 for (y = 0;y < ATTEN2DSIZE;y++)
1028 for (x = 0;x < ATTEN2DSIZE;x++)
1030 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1031 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1033 intensity = 1.0f - sqrt(DotProduct(v, v));
1035 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1036 d = bound(0, intensity, 255);
1037 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1038 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1039 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1040 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1043 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1044 if (r_shadow_texture3d.integer)
1046 for (z = 0;z < ATTEN3DSIZE;z++)
1048 for (y = 0;y < ATTEN3DSIZE;y++)
1050 for (x = 0;x < ATTEN3DSIZE;x++)
1052 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1053 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1054 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1055 intensity = 1.0f - sqrt(DotProduct(v, v));
1057 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1058 d = bound(0, intensity, 255);
1059 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1060 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1061 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1062 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1066 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1071 void R_Shadow_ValidateCvars(void)
1073 if (r_shadow_texture3d.integer && !gl_texture3d)
1074 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1075 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1076 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1079 void R_Shadow_Stage_Begin(void)
1083 R_Shadow_ValidateCvars();
1085 if (!r_shadow_attenuation2dtexture
1086 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1087 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1088 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1089 R_Shadow_MakeTextures();
1091 memset(&m, 0, sizeof(m));
1092 GL_BlendFunc(GL_ONE, GL_ZERO);
1093 GL_DepthMask(false);
1096 GL_Color(0, 0, 0, 1);
1097 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1098 qglEnable(GL_CULL_FACE);
1099 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1100 r_shadowstage = SHADOWSTAGE_NONE;
1103 void R_Shadow_Stage_ShadowVolumes(void)
1106 memset(&m, 0, sizeof(m));
1108 GL_Color(1, 1, 1, 1);
1109 GL_ColorMask(0, 0, 0, 0);
1110 GL_BlendFunc(GL_ONE, GL_ZERO);
1111 GL_DepthMask(false);
1113 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1114 //if (r_shadow_shadow_polygonoffset.value != 0)
1116 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1117 // qglEnable(GL_POLYGON_OFFSET_FILL);
1120 // qglDisable(GL_POLYGON_OFFSET_FILL);
1121 qglDepthFunc(GL_LESS);
1122 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1123 qglEnable(GL_STENCIL_TEST);
1124 qglStencilFunc(GL_ALWAYS, 128, ~0);
1125 if (gl_ext_stenciltwoside.integer)
1127 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1128 qglDisable(GL_CULL_FACE);
1129 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1130 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1132 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1133 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1135 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1139 r_shadowstage = SHADOWSTAGE_STENCIL;
1140 qglEnable(GL_CULL_FACE);
1142 // this is changed by every shadow render so its value here is unimportant
1143 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1145 GL_Clear(GL_STENCIL_BUFFER_BIT);
1147 // LordHavoc note: many shadow volumes reside entirely inside the world
1148 // (that is to say they are entirely bounded by their lit surfaces),
1149 // which can be optimized by handling things as an inverted light volume,
1150 // with the shadow boundaries of the world being simulated by an altered
1151 // (129) bias to stencil clearing on such lights
1152 // FIXME: generate inverted light volumes for use as shadow volumes and
1153 // optimize for them as noted above
1156 void R_Shadow_Stage_Light(int shadowtest)
1159 memset(&m, 0, sizeof(m));
1161 GL_BlendFunc(GL_ONE, GL_ONE);
1162 GL_DepthMask(false);
1164 qglPolygonOffset(0, 0);
1165 //qglDisable(GL_POLYGON_OFFSET_FILL);
1166 GL_Color(1, 1, 1, 1);
1167 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1168 qglDepthFunc(GL_EQUAL);
1169 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1170 qglEnable(GL_CULL_FACE);
1172 qglEnable(GL_STENCIL_TEST);
1174 qglDisable(GL_STENCIL_TEST);
1175 if (gl_support_stenciltwoside)
1176 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1178 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1179 // only draw light where this geometry was already rendered AND the
1180 // stencil is 128 (values other than this mean shadow)
1181 qglStencilFunc(GL_EQUAL, 128, ~0);
1182 r_shadowstage = SHADOWSTAGE_LIGHT;
1186 void R_Shadow_Stage_End(void)
1189 memset(&m, 0, sizeof(m));
1191 GL_BlendFunc(GL_ONE, GL_ZERO);
1194 qglPolygonOffset(0, 0);
1195 //qglDisable(GL_POLYGON_OFFSET_FILL);
1196 GL_Color(1, 1, 1, 1);
1197 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1198 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1199 qglDepthFunc(GL_LEQUAL);
1200 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1201 qglDisable(GL_STENCIL_TEST);
1202 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1203 if (gl_support_stenciltwoside)
1204 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1206 qglStencilFunc(GL_ALWAYS, 128, ~0);
1207 r_shadowstage = SHADOWSTAGE_NONE;
1210 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1212 int i, ix1, iy1, ix2, iy2;
1213 float x1, y1, x2, y2, x, y, f;
1214 vec3_t smins, smaxs;
1216 if (!r_shadow_scissor.integer)
1218 // if view is inside the box, just say yes it's visible
1219 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1221 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1224 for (i = 0;i < 3;i++)
1226 if (r_viewforward[i] >= 0)
1237 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1238 if (DotProduct(r_viewforward, v2) <= f)
1240 // entirely behind nearclip plane
1243 if (DotProduct(r_viewforward, v) >= f)
1245 // entirely infront of nearclip plane
1246 x1 = y1 = x2 = y2 = 0;
1247 for (i = 0;i < 8;i++)
1249 v[0] = (i & 1) ? mins[0] : maxs[0];
1250 v[1] = (i & 2) ? mins[1] : maxs[1];
1251 v[2] = (i & 4) ? mins[2] : maxs[2];
1253 GL_TransformToScreen(v, v2);
1254 //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]);
1273 // clipped by nearclip plane
1274 // this is nasty and crude...
1275 // create viewspace bbox
1276 for (i = 0;i < 8;i++)
1278 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1279 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1280 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1281 v2[0] = -DotProduct(v, r_viewleft);
1282 v2[1] = DotProduct(v, r_viewup);
1283 v2[2] = DotProduct(v, r_viewforward);
1286 if (smins[0] > v2[0]) smins[0] = v2[0];
1287 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1288 if (smins[1] > v2[1]) smins[1] = v2[1];
1289 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1290 if (smins[2] > v2[2]) smins[2] = v2[2];
1291 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1295 smins[0] = smaxs[0] = v2[0];
1296 smins[1] = smaxs[1] = v2[1];
1297 smins[2] = smaxs[2] = v2[2];
1300 // now we have a bbox in viewspace
1301 // clip it to the view plane
1304 // return true if that culled the box
1305 if (smins[2] >= smaxs[2])
1307 // ok some of it is infront of the view, transform each corner back to
1308 // worldspace and then to screenspace and make screen rect
1309 // initialize these variables just to avoid compiler warnings
1310 x1 = y1 = x2 = y2 = 0;
1311 for (i = 0;i < 8;i++)
1313 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1314 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1315 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1316 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1317 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1318 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1320 GL_TransformToScreen(v, v2);
1321 //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]);
1338 // this code doesn't handle boxes with any points behind view properly
1339 x1 = 1000;x2 = -1000;
1340 y1 = 1000;y2 = -1000;
1341 for (i = 0;i < 8;i++)
1343 v[0] = (i & 1) ? mins[0] : maxs[0];
1344 v[1] = (i & 2) ? mins[1] : maxs[1];
1345 v[2] = (i & 4) ? mins[2] : maxs[2];
1347 GL_TransformToScreen(v, v2);
1348 //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]);
1366 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1367 if (ix1 < r_view_x) ix1 = r_view_x;
1368 if (iy1 < r_view_y) iy1 = r_view_y;
1369 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1370 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1371 if (ix2 <= ix1 || iy2 <= iy1)
1373 // set up the scissor rectangle
1374 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1375 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1376 //qglEnable(GL_SCISSOR_TEST);
1381 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1383 float *color4f = varray_color4f;
1384 float dist, dot, intensity, v[3], n[3];
1385 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1387 Matrix4x4_Transform(m, vertex3f, v);
1388 if ((dist = DotProduct(v, v)) < 1)
1390 Matrix4x4_Transform3x3(m, normal3f, n);
1391 if ((dot = DotProduct(n, v)) > 0)
1394 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1395 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1396 VectorScale(lightcolor, intensity, color4f);
1401 VectorClear(color4f);
1407 VectorClear(color4f);
1413 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1415 float *color4f = varray_color4f;
1416 float dist, dot, intensity, v[3], n[3];
1417 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1419 Matrix4x4_Transform(m, vertex3f, v);
1420 if ((dist = fabs(v[2])) < 1)
1422 Matrix4x4_Transform3x3(m, normal3f, n);
1423 if ((dot = DotProduct(n, v)) > 0)
1425 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1426 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1427 VectorScale(lightcolor, intensity, color4f);
1432 VectorClear(color4f);
1438 VectorClear(color4f);
1444 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1446 float *color4f = varray_color4f;
1447 float dot, intensity, v[3], n[3];
1448 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1450 Matrix4x4_Transform(m, vertex3f, v);
1451 Matrix4x4_Transform3x3(m, normal3f, n);
1452 if ((dot = DotProduct(n, v)) > 0)
1454 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1455 VectorScale(lightcolor, intensity, color4f);
1460 VectorClear(color4f);
1466 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1468 float *color4f = varray_color4f;
1469 float dist, intensity, v[3];
1470 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1472 Matrix4x4_Transform(m, vertex3f, v);
1473 if ((dist = DotProduct(v, v)) < 1)
1476 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1477 VectorScale(lightcolor, intensity, color4f);
1482 VectorClear(color4f);
1488 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1490 float *color4f = varray_color4f;
1491 float dist, intensity, v[3];
1492 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1494 Matrix4x4_Transform(m, vertex3f, v);
1495 if ((dist = fabs(v[2])) < 1)
1497 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1498 VectorScale(lightcolor, intensity, color4f);
1503 VectorClear(color4f);
1509 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1510 #define USETEXMATRIX
1512 #ifndef USETEXMATRIX
1513 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1514 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1515 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1519 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1520 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1521 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1528 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1532 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1533 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1541 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)
1545 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1547 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1548 // the cubemap normalizes this for us
1549 out3f[0] = DotProduct(svector3f, lightdir);
1550 out3f[1] = DotProduct(tvector3f, lightdir);
1551 out3f[2] = DotProduct(normal3f, lightdir);
1555 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)
1558 float lightdir[3], eyedir[3], halfdir[3];
1559 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1561 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1562 VectorNormalizeFast(lightdir);
1563 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1564 VectorNormalizeFast(eyedir);
1565 VectorAdd(lightdir, eyedir, halfdir);
1566 // the cubemap normalizes this for us
1567 out3f[0] = DotProduct(svector3f, halfdir);
1568 out3f[1] = DotProduct(tvector3f, halfdir);
1569 out3f[2] = DotProduct(normal3f, halfdir);
1573 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)
1576 float color[3], color2[3], colorscale;
1578 // FIXME: support EF_NODEPTHTEST
1579 GL_DepthMask(false);
1582 bumptexture = r_shadow_blankbumptexture;
1583 specularscale *= r_shadow_glossintensity.value;
1586 if (r_shadow_gloss.integer >= 2)
1588 glosstexture = r_shadow_blankglosstexture;
1589 specularscale *= r_shadow_gloss2intensity.value;
1593 glosstexture = r_shadow_blankblacktexture;
1597 if (r_shadow_gloss.integer < 1)
1600 lightcubemap = r_shadow_blankwhitecubetexture;
1601 if (ambientscale + diffusescale + specularscale < 0.01)
1603 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1605 unsigned int perm, prog;
1606 // GLSL shader path (GFFX5200, Radeon 9500)
1607 memset(&m, 0, sizeof(m));
1608 m.pointer_vertex = vertex3f;
1609 m.pointer_texcoord[0] = texcoord2f;
1610 m.pointer_texcoord3f[1] = svector3f;
1611 m.pointer_texcoord3f[2] = tvector3f;
1612 m.pointer_texcoord3f[3] = normal3f;
1613 m.tex[0] = R_GetTexture(bumptexture);
1614 m.tex[1] = R_GetTexture(basetexture);
1615 m.tex[2] = R_GetTexture(glosstexture);
1616 m.texcubemap[3] = R_GetTexture(lightcubemap);
1617 // TODO: support fog (after renderer is converted to texture fog)
1618 m.tex[4] = R_GetTexture(r_shadow_blankwhitetexture);
1619 m.texmatrix[3] = *matrix_modeltolight;
1621 GL_BlendFunc(GL_ONE, GL_ONE);
1622 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1626 perm |= SHADERPERMUTATION_SPECULAR;
1628 // perm |= SHADERPERMUTATION_FOG;
1630 perm |= SHADERPERMUTATION_CUBEFILTER;
1631 if (r_shadow_glsl_offsetmapping.integer)
1632 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1633 prog = r_shadow_program_light[perm];
1634 qglUseProgramObjectARB(r_shadow_program_light[perm]);
1635 // TODO: support fog (after renderer is converted to texture fog)
1636 if (perm & SHADERPERMUTATION_FOG)
1637 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);
1638 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);
1639 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);
1640 if (perm & SHADERPERMUTATION_SPECULAR)
1642 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);
1643 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);
1645 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);
1646 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);
1647 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1648 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);
1649 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1651 // these are * 0.25 because the offsetmapping shader does the process 4 times
1652 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value * 0.25);
1653 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value * 0.25);
1656 GL_LockArrays(0, numverts);
1657 R_Mesh_Draw(numverts, numtriangles, elements);
1659 c_rt_lighttris += numtriangles;
1660 GL_LockArrays(0, 0);
1661 qglUseProgramObjectARB(0);
1663 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1666 bumptexture = r_shadow_blankbumptexture;
1668 glosstexture = r_shadow_blankglosstexture;
1672 colorscale = ambientscale;
1673 // colorscale accounts for how much we multiply the brightness
1676 // mult is how many times the final pass of the lighting will be
1677 // performed to get more brightness than otherwise possible.
1679 // Limit mult to 64 for sanity sake.
1680 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1682 // 3 3D combine path (Geforce3, Radeon 8500)
1683 memset(&m, 0, sizeof(m));
1684 m.pointer_vertex = vertex3f;
1685 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1687 m.pointer_texcoord3f[0] = vertex3f;
1688 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1690 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1691 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1693 m.tex[1] = R_GetTexture(basetexture);
1694 m.pointer_texcoord[1] = texcoord2f;
1695 m.texcubemap[2] = R_GetTexture(lightcubemap);
1697 m.pointer_texcoord3f[2] = vertex3f;
1698 m.texmatrix[2] = *matrix_modeltolight;
1700 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1701 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1703 GL_BlendFunc(GL_ONE, GL_ONE);
1705 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1707 // 2 3D combine path (Geforce3, original Radeon)
1708 memset(&m, 0, sizeof(m));
1709 m.pointer_vertex = vertex3f;
1710 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1712 m.pointer_texcoord3f[0] = vertex3f;
1713 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1715 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1716 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1718 m.tex[1] = R_GetTexture(basetexture);
1719 m.pointer_texcoord[1] = texcoord2f;
1720 GL_BlendFunc(GL_ONE, GL_ONE);
1722 else if (r_textureunits.integer >= 4 && lightcubemap)
1724 // 4 2D combine path (Geforce3, Radeon 8500)
1725 memset(&m, 0, sizeof(m));
1726 m.pointer_vertex = vertex3f;
1727 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1729 m.pointer_texcoord3f[0] = vertex3f;
1730 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1732 m.pointer_texcoord[0] = varray_texcoord2f[0];
1733 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1735 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1737 m.pointer_texcoord3f[1] = vertex3f;
1738 m.texmatrix[1] = *matrix_modeltoattenuationz;
1740 m.pointer_texcoord[1] = varray_texcoord2f[1];
1741 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1743 m.tex[2] = R_GetTexture(basetexture);
1744 m.pointer_texcoord[2] = texcoord2f;
1747 m.texcubemap[3] = R_GetTexture(lightcubemap);
1749 m.pointer_texcoord3f[3] = vertex3f;
1750 m.texmatrix[3] = *matrix_modeltolight;
1752 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1753 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1756 GL_BlendFunc(GL_ONE, GL_ONE);
1758 else if (r_textureunits.integer >= 3 && !lightcubemap)
1760 // 3 2D combine path (Geforce3, original Radeon)
1761 memset(&m, 0, sizeof(m));
1762 m.pointer_vertex = vertex3f;
1763 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1765 m.pointer_texcoord3f[0] = vertex3f;
1766 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1768 m.pointer_texcoord[0] = varray_texcoord2f[0];
1769 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1771 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1773 m.pointer_texcoord3f[1] = vertex3f;
1774 m.texmatrix[1] = *matrix_modeltoattenuationz;
1776 m.pointer_texcoord[1] = varray_texcoord2f[1];
1777 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1779 m.tex[2] = R_GetTexture(basetexture);
1780 m.pointer_texcoord[2] = texcoord2f;
1781 GL_BlendFunc(GL_ONE, GL_ONE);
1785 // 2/2/2 2D combine path (any dot3 card)
1786 memset(&m, 0, sizeof(m));
1787 m.pointer_vertex = vertex3f;
1788 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1790 m.pointer_texcoord3f[0] = vertex3f;
1791 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1793 m.pointer_texcoord[0] = varray_texcoord2f[0];
1794 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1796 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1798 m.pointer_texcoord3f[1] = vertex3f;
1799 m.texmatrix[1] = *matrix_modeltoattenuationz;
1801 m.pointer_texcoord[1] = varray_texcoord2f[1];
1802 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1805 GL_ColorMask(0,0,0,1);
1806 GL_BlendFunc(GL_ONE, GL_ZERO);
1807 GL_LockArrays(0, numverts);
1808 R_Mesh_Draw(numverts, numtriangles, elements);
1809 GL_LockArrays(0, 0);
1811 c_rt_lighttris += numtriangles;
1813 memset(&m, 0, sizeof(m));
1814 m.pointer_vertex = vertex3f;
1815 m.tex[0] = R_GetTexture(basetexture);
1816 m.pointer_texcoord[0] = texcoord2f;
1819 m.texcubemap[1] = R_GetTexture(lightcubemap);
1821 m.pointer_texcoord3f[1] = vertex3f;
1822 m.texmatrix[1] = *matrix_modeltolight;
1824 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1825 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1828 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1830 // this final code is shared
1832 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1833 VectorScale(lightcolor, colorscale, color2);
1834 GL_LockArrays(0, numverts);
1835 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1837 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1838 R_Mesh_Draw(numverts, numtriangles, elements);
1840 c_rt_lighttris += numtriangles;
1842 GL_LockArrays(0, 0);
1847 colorscale = diffusescale;
1848 // colorscale accounts for how much we multiply the brightness
1851 // mult is how many times the final pass of the lighting will be
1852 // performed to get more brightness than otherwise possible.
1854 // Limit mult to 64 for sanity sake.
1855 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1857 // 3/2 3D combine path (Geforce3, Radeon 8500)
1858 memset(&m, 0, sizeof(m));
1859 m.pointer_vertex = vertex3f;
1860 m.tex[0] = R_GetTexture(bumptexture);
1861 m.texcombinergb[0] = GL_REPLACE;
1862 m.pointer_texcoord[0] = texcoord2f;
1863 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1864 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1865 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1866 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1867 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1869 m.pointer_texcoord3f[2] = vertex3f;
1870 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1872 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1873 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1876 GL_ColorMask(0,0,0,1);
1877 GL_BlendFunc(GL_ONE, GL_ZERO);
1878 GL_LockArrays(0, numverts);
1879 R_Mesh_Draw(numverts, numtriangles, elements);
1880 GL_LockArrays(0, 0);
1882 c_rt_lighttris += numtriangles;
1884 memset(&m, 0, sizeof(m));
1885 m.pointer_vertex = vertex3f;
1886 m.tex[0] = R_GetTexture(basetexture);
1887 m.pointer_texcoord[0] = texcoord2f;
1890 m.texcubemap[1] = R_GetTexture(lightcubemap);
1892 m.pointer_texcoord3f[1] = vertex3f;
1893 m.texmatrix[1] = *matrix_modeltolight;
1895 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1896 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1899 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1901 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1903 // 1/2/2 3D combine path (original Radeon)
1904 memset(&m, 0, sizeof(m));
1905 m.pointer_vertex = vertex3f;
1906 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1908 m.pointer_texcoord3f[0] = vertex3f;
1909 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1911 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1912 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1915 GL_ColorMask(0,0,0,1);
1916 GL_BlendFunc(GL_ONE, GL_ZERO);
1917 GL_LockArrays(0, numverts);
1918 R_Mesh_Draw(numverts, numtriangles, elements);
1919 GL_LockArrays(0, 0);
1921 c_rt_lighttris += numtriangles;
1923 memset(&m, 0, sizeof(m));
1924 m.pointer_vertex = vertex3f;
1925 m.tex[0] = R_GetTexture(bumptexture);
1926 m.texcombinergb[0] = GL_REPLACE;
1927 m.pointer_texcoord[0] = texcoord2f;
1928 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1929 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1930 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1931 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1933 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1934 GL_LockArrays(0, numverts);
1935 R_Mesh_Draw(numverts, numtriangles, elements);
1936 GL_LockArrays(0, 0);
1938 c_rt_lighttris += numtriangles;
1940 memset(&m, 0, sizeof(m));
1941 m.pointer_vertex = vertex3f;
1942 m.tex[0] = R_GetTexture(basetexture);
1943 m.pointer_texcoord[0] = texcoord2f;
1946 m.texcubemap[1] = R_GetTexture(lightcubemap);
1948 m.pointer_texcoord3f[1] = vertex3f;
1949 m.texmatrix[1] = *matrix_modeltolight;
1951 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1952 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1955 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1957 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1959 // 2/2 3D combine path (original Radeon)
1960 memset(&m, 0, sizeof(m));
1961 m.pointer_vertex = vertex3f;
1962 m.tex[0] = R_GetTexture(bumptexture);
1963 m.texcombinergb[0] = GL_REPLACE;
1964 m.pointer_texcoord[0] = texcoord2f;
1965 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1966 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1967 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1968 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1970 GL_ColorMask(0,0,0,1);
1971 GL_BlendFunc(GL_ONE, GL_ZERO);
1972 GL_LockArrays(0, numverts);
1973 R_Mesh_Draw(numverts, numtriangles, elements);
1974 GL_LockArrays(0, 0);
1976 c_rt_lighttris += numtriangles;
1978 memset(&m, 0, sizeof(m));
1979 m.pointer_vertex = vertex3f;
1980 m.tex[0] = R_GetTexture(basetexture);
1981 m.pointer_texcoord[0] = texcoord2f;
1982 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1984 m.pointer_texcoord3f[1] = vertex3f;
1985 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1987 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1988 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1990 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1992 else if (r_textureunits.integer >= 4)
1994 // 4/2 2D combine path (Geforce3, Radeon 8500)
1995 memset(&m, 0, sizeof(m));
1996 m.pointer_vertex = vertex3f;
1997 m.tex[0] = R_GetTexture(bumptexture);
1998 m.texcombinergb[0] = GL_REPLACE;
1999 m.pointer_texcoord[0] = texcoord2f;
2000 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2001 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2002 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2003 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2004 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2006 m.pointer_texcoord3f[2] = vertex3f;
2007 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2009 m.pointer_texcoord[2] = varray_texcoord2f[2];
2010 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2012 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2014 m.pointer_texcoord3f[3] = vertex3f;
2015 m.texmatrix[3] = *matrix_modeltoattenuationz;
2017 m.pointer_texcoord[3] = varray_texcoord2f[3];
2018 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2021 GL_ColorMask(0,0,0,1);
2022 GL_BlendFunc(GL_ONE, GL_ZERO);
2023 GL_LockArrays(0, numverts);
2024 R_Mesh_Draw(numverts, numtriangles, elements);
2025 GL_LockArrays(0, 0);
2027 c_rt_lighttris += numtriangles;
2029 memset(&m, 0, sizeof(m));
2030 m.pointer_vertex = vertex3f;
2031 m.tex[0] = R_GetTexture(basetexture);
2032 m.pointer_texcoord[0] = texcoord2f;
2035 m.texcubemap[1] = R_GetTexture(lightcubemap);
2037 m.pointer_texcoord3f[1] = vertex3f;
2038 m.texmatrix[1] = *matrix_modeltolight;
2040 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2041 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2044 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2048 // 2/2/2 2D combine path (any dot3 card)
2049 memset(&m, 0, sizeof(m));
2050 m.pointer_vertex = vertex3f;
2051 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2053 m.pointer_texcoord3f[0] = vertex3f;
2054 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2056 m.pointer_texcoord[0] = varray_texcoord2f[0];
2057 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2059 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2061 m.pointer_texcoord3f[1] = vertex3f;
2062 m.texmatrix[1] = *matrix_modeltoattenuationz;
2064 m.pointer_texcoord[1] = varray_texcoord2f[1];
2065 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2068 GL_ColorMask(0,0,0,1);
2069 GL_BlendFunc(GL_ONE, GL_ZERO);
2070 GL_LockArrays(0, numverts);
2071 R_Mesh_Draw(numverts, numtriangles, elements);
2072 GL_LockArrays(0, 0);
2074 c_rt_lighttris += numtriangles;
2076 memset(&m, 0, sizeof(m));
2077 m.pointer_vertex = vertex3f;
2078 m.tex[0] = R_GetTexture(bumptexture);
2079 m.texcombinergb[0] = GL_REPLACE;
2080 m.pointer_texcoord[0] = texcoord2f;
2081 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2082 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2083 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2084 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2086 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2087 GL_LockArrays(0, numverts);
2088 R_Mesh_Draw(numverts, numtriangles, elements);
2089 GL_LockArrays(0, 0);
2091 c_rt_lighttris += numtriangles;
2093 memset(&m, 0, sizeof(m));
2094 m.pointer_vertex = vertex3f;
2095 m.tex[0] = R_GetTexture(basetexture);
2096 m.pointer_texcoord[0] = texcoord2f;
2099 m.texcubemap[1] = R_GetTexture(lightcubemap);
2101 m.pointer_texcoord3f[1] = vertex3f;
2102 m.texmatrix[1] = *matrix_modeltolight;
2104 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2105 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2108 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2110 // this final code is shared
2112 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2113 VectorScale(lightcolor, colorscale, color2);
2114 GL_LockArrays(0, numverts);
2115 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2117 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2118 R_Mesh_Draw(numverts, numtriangles, elements);
2120 c_rt_lighttris += numtriangles;
2122 GL_LockArrays(0, 0);
2124 if (specularscale && glosstexture != r_shadow_blankblacktexture)
2126 // FIXME: detect blendsquare!
2127 //if (gl_support_blendsquare)
2129 colorscale = specularscale;
2131 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2133 // 2/0/0/1/2 3D combine blendsquare path
2134 memset(&m, 0, sizeof(m));
2135 m.pointer_vertex = vertex3f;
2136 m.tex[0] = R_GetTexture(bumptexture);
2137 m.pointer_texcoord[0] = texcoord2f;
2138 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2139 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2140 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2141 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2143 GL_ColorMask(0,0,0,1);
2144 // this squares the result
2145 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2146 GL_LockArrays(0, numverts);
2147 R_Mesh_Draw(numverts, numtriangles, elements);
2148 GL_LockArrays(0, 0);
2150 c_rt_lighttris += numtriangles;
2152 memset(&m, 0, sizeof(m));
2153 m.pointer_vertex = vertex3f;
2155 GL_LockArrays(0, numverts);
2156 // square alpha in framebuffer a few times to make it shiny
2157 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2158 // these comments are a test run through this math for intensity 0.5
2159 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2160 // 0.25 * 0.25 = 0.0625 (this is another pass)
2161 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2162 R_Mesh_Draw(numverts, numtriangles, elements);
2164 c_rt_lighttris += numtriangles;
2165 R_Mesh_Draw(numverts, numtriangles, elements);
2167 c_rt_lighttris += numtriangles;
2168 GL_LockArrays(0, 0);
2170 memset(&m, 0, sizeof(m));
2171 m.pointer_vertex = vertex3f;
2172 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2174 m.pointer_texcoord3f[0] = vertex3f;
2175 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2177 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2178 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2181 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2182 GL_LockArrays(0, numverts);
2183 R_Mesh_Draw(numverts, numtriangles, elements);
2184 GL_LockArrays(0, 0);
2186 c_rt_lighttris += numtriangles;
2188 memset(&m, 0, sizeof(m));
2189 m.pointer_vertex = vertex3f;
2190 m.tex[0] = R_GetTexture(glosstexture);
2191 m.pointer_texcoord[0] = texcoord2f;
2194 m.texcubemap[1] = R_GetTexture(lightcubemap);
2196 m.pointer_texcoord3f[1] = vertex3f;
2197 m.texmatrix[1] = *matrix_modeltolight;
2199 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2200 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2203 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2205 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2207 // 2/0/0/2 3D combine blendsquare path
2208 memset(&m, 0, sizeof(m));
2209 m.pointer_vertex = vertex3f;
2210 m.tex[0] = R_GetTexture(bumptexture);
2211 m.pointer_texcoord[0] = texcoord2f;
2212 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2213 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2214 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2215 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2217 GL_ColorMask(0,0,0,1);
2218 // this squares the result
2219 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2220 GL_LockArrays(0, numverts);
2221 R_Mesh_Draw(numverts, numtriangles, elements);
2222 GL_LockArrays(0, 0);
2224 c_rt_lighttris += numtriangles;
2226 memset(&m, 0, sizeof(m));
2227 m.pointer_vertex = vertex3f;
2229 GL_LockArrays(0, numverts);
2230 // square alpha in framebuffer a few times to make it shiny
2231 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2232 // these comments are a test run through this math for intensity 0.5
2233 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2234 // 0.25 * 0.25 = 0.0625 (this is another pass)
2235 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2236 R_Mesh_Draw(numverts, numtriangles, elements);
2238 c_rt_lighttris += numtriangles;
2239 R_Mesh_Draw(numverts, numtriangles, elements);
2241 c_rt_lighttris += numtriangles;
2242 GL_LockArrays(0, 0);
2244 memset(&m, 0, sizeof(m));
2245 m.pointer_vertex = vertex3f;
2246 m.tex[0] = R_GetTexture(glosstexture);
2247 m.pointer_texcoord[0] = texcoord2f;
2248 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2250 m.pointer_texcoord3f[1] = vertex3f;
2251 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2253 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2254 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2256 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2260 // 2/0/0/2/2 2D combine blendsquare path
2261 memset(&m, 0, sizeof(m));
2262 m.pointer_vertex = vertex3f;
2263 m.tex[0] = R_GetTexture(bumptexture);
2264 m.pointer_texcoord[0] = texcoord2f;
2265 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2266 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2267 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2268 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2270 GL_ColorMask(0,0,0,1);
2271 // this squares the result
2272 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2273 GL_LockArrays(0, numverts);
2274 R_Mesh_Draw(numverts, numtriangles, elements);
2275 GL_LockArrays(0, 0);
2277 c_rt_lighttris += numtriangles;
2279 memset(&m, 0, sizeof(m));
2280 m.pointer_vertex = vertex3f;
2282 GL_LockArrays(0, numverts);
2283 // square alpha in framebuffer a few times to make it shiny
2284 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2285 // these comments are a test run through this math for intensity 0.5
2286 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2287 // 0.25 * 0.25 = 0.0625 (this is another pass)
2288 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2289 R_Mesh_Draw(numverts, numtriangles, elements);
2291 c_rt_lighttris += numtriangles;
2292 R_Mesh_Draw(numverts, numtriangles, elements);
2294 c_rt_lighttris += numtriangles;
2295 GL_LockArrays(0, 0);
2297 memset(&m, 0, sizeof(m));
2298 m.pointer_vertex = vertex3f;
2299 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2301 m.pointer_texcoord3f[0] = vertex3f;
2302 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2304 m.pointer_texcoord[0] = varray_texcoord2f[0];
2305 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2307 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2309 m.pointer_texcoord3f[1] = vertex3f;
2310 m.texmatrix[1] = *matrix_modeltoattenuationz;
2312 m.pointer_texcoord[1] = varray_texcoord2f[1];
2313 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2316 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2317 GL_LockArrays(0, numverts);
2318 R_Mesh_Draw(numverts, numtriangles, elements);
2319 GL_LockArrays(0, 0);
2321 c_rt_lighttris += numtriangles;
2323 memset(&m, 0, sizeof(m));
2324 m.pointer_vertex = vertex3f;
2325 m.tex[0] = R_GetTexture(glosstexture);
2326 m.pointer_texcoord[0] = texcoord2f;
2329 m.texcubemap[1] = R_GetTexture(lightcubemap);
2331 m.pointer_texcoord3f[1] = vertex3f;
2332 m.texmatrix[1] = *matrix_modeltolight;
2334 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2335 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2338 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2341 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2342 VectorScale(lightcolor, colorscale, color2);
2343 GL_LockArrays(0, numverts);
2344 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2346 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2347 R_Mesh_Draw(numverts, numtriangles, elements);
2349 c_rt_lighttris += numtriangles;
2351 GL_LockArrays(0, 0);
2359 GL_BlendFunc(GL_ONE, GL_ONE);
2360 VectorScale(lightcolor, ambientscale, color2);
2361 memset(&m, 0, sizeof(m));
2362 m.pointer_vertex = vertex3f;
2363 m.tex[0] = R_GetTexture(basetexture);
2364 m.pointer_texcoord[0] = texcoord2f;
2365 if (r_textureunits.integer >= 2)
2368 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2370 m.pointer_texcoord3f[1] = vertex3f;
2371 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2373 m.pointer_texcoord[1] = varray_texcoord2f[1];
2374 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2376 if (r_textureunits.integer >= 3)
2378 // Geforce3/Radeon class but not using dot3
2379 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2381 m.pointer_texcoord3f[2] = vertex3f;
2382 m.texmatrix[2] = *matrix_modeltoattenuationz;
2384 m.pointer_texcoord[2] = varray_texcoord2f[2];
2385 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2389 if (r_textureunits.integer >= 3)
2390 m.pointer_color = NULL;
2392 m.pointer_color = varray_color4f;
2394 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2396 color[0] = bound(0, color2[0], 1);
2397 color[1] = bound(0, color2[1], 1);
2398 color[2] = bound(0, color2[2], 1);
2399 if (r_textureunits.integer >= 3)
2400 GL_Color(color[0], color[1], color[2], 1);
2401 else if (r_textureunits.integer >= 2)
2402 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2404 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2405 GL_LockArrays(0, numverts);
2406 R_Mesh_Draw(numverts, numtriangles, elements);
2407 GL_LockArrays(0, 0);
2409 c_rt_lighttris += numtriangles;
2414 GL_BlendFunc(GL_ONE, GL_ONE);
2415 VectorScale(lightcolor, diffusescale, color2);
2416 memset(&m, 0, sizeof(m));
2417 m.pointer_vertex = vertex3f;
2418 m.pointer_color = varray_color4f;
2419 m.tex[0] = R_GetTexture(basetexture);
2420 m.pointer_texcoord[0] = texcoord2f;
2421 if (r_textureunits.integer >= 2)
2424 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2426 m.pointer_texcoord3f[1] = vertex3f;
2427 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2429 m.pointer_texcoord[1] = varray_texcoord2f[1];
2430 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2432 if (r_textureunits.integer >= 3)
2434 // Geforce3/Radeon class but not using dot3
2435 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2437 m.pointer_texcoord3f[2] = vertex3f;
2438 m.texmatrix[2] = *matrix_modeltoattenuationz;
2440 m.pointer_texcoord[2] = varray_texcoord2f[2];
2441 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2446 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2448 color[0] = bound(0, color2[0], 1);
2449 color[1] = bound(0, color2[1], 1);
2450 color[2] = bound(0, color2[2], 1);
2451 if (r_textureunits.integer >= 3)
2452 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2453 else if (r_textureunits.integer >= 2)
2454 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2456 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2457 GL_LockArrays(0, numverts);
2458 R_Mesh_Draw(numverts, numtriangles, elements);
2459 GL_LockArrays(0, 0);
2461 c_rt_lighttris += numtriangles;
2467 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2471 R_RTLight_Uncompile(rtlight);
2472 memset(rtlight, 0, sizeof(*rtlight));
2474 VectorCopy(light->origin, rtlight->shadoworigin);
2475 VectorCopy(light->color, rtlight->color);
2476 rtlight->radius = light->radius;
2477 //rtlight->cullradius = rtlight->radius;
2478 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2479 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2480 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2481 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2482 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2483 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2484 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2485 rtlight->cubemapname[0] = 0;
2486 if (light->cubemapname[0])
2487 strcpy(rtlight->cubemapname, light->cubemapname);
2488 else if (light->cubemapnum > 0)
2489 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2490 rtlight->shadow = light->shadow;
2491 rtlight->corona = light->corona;
2492 rtlight->style = light->style;
2493 rtlight->isstatic = isstatic;
2494 rtlight->coronasizescale = light->coronasizescale;
2495 rtlight->ambientscale = light->ambientscale;
2496 rtlight->diffusescale = light->diffusescale;
2497 rtlight->specularscale = light->specularscale;
2498 rtlight->flags = light->flags;
2499 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2500 // ConcatScale won't work here because this needs to scale rotate and
2501 // translate, not just rotate
2502 scale = 1.0f / rtlight->radius;
2503 for (k = 0;k < 3;k++)
2504 for (j = 0;j < 4;j++)
2505 rtlight->matrix_worldtolight.m[k][j] *= scale;
2506 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2507 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2509 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2510 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2511 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2512 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2515 // compiles rtlight geometry
2516 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2517 void R_RTLight_Compile(rtlight_t *rtlight)
2519 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2520 entity_render_t *ent = &cl_entities[0].render;
2521 model_t *model = ent->model;
2523 // compile the light
2524 rtlight->compiled = true;
2525 rtlight->static_numclusters = 0;
2526 rtlight->static_numclusterpvsbytes = 0;
2527 rtlight->static_clusterlist = NULL;
2528 rtlight->static_clusterpvs = NULL;
2529 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2530 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2531 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2532 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2533 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2534 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2536 if (model && model->GetLightInfo)
2538 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2539 r_shadow_compilingrtlight = rtlight;
2540 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2541 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2542 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);
2543 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2544 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2547 rtlight->static_numclusters = numclusters;
2548 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2549 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2550 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2552 if (model->DrawShadowVolume && rtlight->shadow)
2554 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2555 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2556 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2558 if (model->DrawLight)
2560 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2561 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);
2562 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2564 // switch back to rendering when DrawShadowVolume or DrawLight is called
2565 r_shadow_compilingrtlight = NULL;
2569 // use smallest available cullradius - box radius or light radius
2570 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2571 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2575 if (rtlight->static_meshchain_shadow)
2578 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2581 shadowtris += mesh->numtriangles;
2587 if (rtlight->static_meshchain_light)
2590 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2593 lighttris += mesh->numtriangles;
2597 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);
2600 void R_RTLight_Uncompile(rtlight_t *rtlight)
2602 if (rtlight->compiled)
2604 if (rtlight->static_meshchain_shadow)
2605 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2606 rtlight->static_meshchain_shadow = NULL;
2607 if (rtlight->static_meshchain_light)
2608 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2609 rtlight->static_meshchain_light = NULL;
2610 if (rtlight->static_clusterlist)
2611 Mem_Free(rtlight->static_clusterlist);
2612 rtlight->static_clusterlist = NULL;
2613 if (rtlight->static_clusterpvs)
2614 Mem_Free(rtlight->static_clusterpvs);
2615 rtlight->static_clusterpvs = NULL;
2616 rtlight->static_numclusters = 0;
2617 rtlight->static_numclusterpvsbytes = 0;
2618 rtlight->compiled = false;
2622 void R_Shadow_UncompileWorldLights(void)
2625 for (light = r_shadow_worldlightchain;light;light = light->next)
2626 R_RTLight_Uncompile(&light->rtlight);
2629 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2631 int i, shadow, usestencil;
2632 entity_render_t *ent;
2634 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2635 rtexture_t *cubemaptexture;
2636 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2637 int numclusters, numsurfaces;
2638 int *clusterlist, *surfacelist;
2640 vec3_t cullmins, cullmaxs;
2644 // skip lights that don't light (corona only lights)
2645 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2648 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2649 VectorScale(rtlight->color, f, lightcolor);
2650 if (VectorLength2(lightcolor) < 0.01)
2653 if (rtlight->selected)
2655 f = 2 + sin(realtime * M_PI * 4.0);
2656 VectorScale(lightcolor, f, lightcolor);
2660 // loading is done before visibility checks because loading should happen
2661 // all at once at the start of a level, not when it stalls gameplay.
2662 // (especially important to benchmarks)
2663 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2664 R_RTLight_Compile(rtlight);
2665 if (rtlight->cubemapname[0])
2666 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2668 cubemaptexture = NULL;
2670 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2671 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2672 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2673 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2674 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2675 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2676 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2683 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2685 // compiled light, world available and can receive realtime lighting
2686 // retrieve cluster information
2687 numclusters = rtlight->static_numclusters;
2688 clusterlist = rtlight->static_clusterlist;
2689 clusterpvs = rtlight->static_clusterpvs;
2690 VectorCopy(rtlight->cullmins, cullmins);
2691 VectorCopy(rtlight->cullmaxs, cullmaxs);
2693 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2695 // dynamic light, world available and can receive realtime lighting
2696 // if the light box is offscreen, skip it right away
2697 if (R_CullBox(cullmins, cullmaxs))
2699 // calculate lit surfaces and clusters
2700 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2701 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2702 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);
2703 clusterlist = r_shadow_buffer_clusterlist;
2704 clusterpvs = r_shadow_buffer_clusterpvs;
2705 surfacelist = r_shadow_buffer_surfacelist;
2707 // if the reduced cluster bounds are offscreen, skip it
2708 if (R_CullBox(cullmins, cullmaxs))
2710 // check if light is illuminating any visible clusters
2713 for (i = 0;i < numclusters;i++)
2714 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2716 if (i == numclusters)
2719 // set up a scissor rectangle for this light
2720 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2723 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2726 if (shadow && (gl_stencil || visiblevolumes))
2728 if (!visiblevolumes)
2730 R_Shadow_Stage_ShadowVolumes();
2733 ent = &cl_entities[0].render;
2734 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2736 memset(&m, 0, sizeof(m));
2737 R_Mesh_Matrix(&ent->matrix);
2738 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2740 m.pointer_vertex = mesh->vertex3f;
2742 GL_LockArrays(0, mesh->numverts);
2743 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2745 // increment stencil if backface is behind depthbuffer
2746 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2747 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2748 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2749 c_rtcached_shadowmeshes++;
2750 c_rtcached_shadowtris += mesh->numtriangles;
2751 // decrement stencil if frontface is behind depthbuffer
2752 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2753 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2755 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2756 c_rtcached_shadowmeshes++;
2757 c_rtcached_shadowtris += mesh->numtriangles;
2758 GL_LockArrays(0, 0);
2761 else if (numsurfaces)
2763 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2764 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2766 if (r_drawentities.integer)
2768 for (i = 0;i < r_refdef.numentities;i++)
2770 ent = r_refdef.entities[i];
2772 if (r_shadow_cull.integer)
2774 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2776 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2779 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2781 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2782 // light emitting entities should not cast their own shadow
2783 if (VectorLength2(relativelightorigin) < 0.1)
2785 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2790 if (!visiblevolumes)
2792 R_Shadow_Stage_Light(usestencil);
2794 ent = &cl_entities[0].render;
2795 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2797 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2798 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2799 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2800 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2801 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2802 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2803 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2804 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2805 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2807 R_Mesh_Matrix(&ent->matrix);
2808 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2809 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);
2812 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2814 if (r_drawentities.integer)
2816 for (i = 0;i < r_refdef.numentities;i++)
2818 ent = r_refdef.entities[i];
2819 // can't draw transparent entity lighting here because
2820 // transparent meshes are deferred for later
2821 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)
2823 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2824 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2825 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2826 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2827 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2828 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2829 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2830 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2831 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);
2838 void R_ShadowVolumeLighting(int visiblevolumes)
2844 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2845 R_Shadow_EditLights_Reload_f();
2849 memset(&m, 0, sizeof(m));
2852 GL_BlendFunc(GL_ONE, GL_ONE);
2853 GL_DepthMask(false);
2854 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2855 qglDisable(GL_CULL_FACE);
2856 GL_Color(0.0, 0.0125, 0.1, 1);
2859 R_Shadow_Stage_Begin();
2860 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2861 if (r_shadow_debuglight.integer >= 0)
2863 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2864 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2865 R_DrawRTLight(&light->rtlight, visiblevolumes);
2868 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2869 if (light->flags & flag)
2870 R_DrawRTLight(&light->rtlight, visiblevolumes);
2872 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2873 R_DrawRTLight(&light->rtlight, visiblevolumes);
2877 qglEnable(GL_CULL_FACE);
2878 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2881 R_Shadow_Stage_End();
2884 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2885 typedef struct suffixinfo_s
2888 qboolean flipx, flipy, flipdiagonal;
2891 static suffixinfo_t suffix[3][6] =
2894 {"px", false, false, false},
2895 {"nx", false, false, false},
2896 {"py", false, false, false},
2897 {"ny", false, false, false},
2898 {"pz", false, false, false},
2899 {"nz", false, false, false}
2902 {"posx", false, false, false},
2903 {"negx", false, false, false},
2904 {"posy", false, false, false},
2905 {"negy", false, false, false},
2906 {"posz", false, false, false},
2907 {"negz", false, false, false}
2910 {"rt", true, false, true},
2911 {"lf", false, true, true},
2912 {"ft", true, true, false},
2913 {"bk", false, false, false},
2914 {"up", true, false, true},
2915 {"dn", true, false, true}
2919 static int componentorder[4] = {0, 1, 2, 3};
2921 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2923 int i, j, cubemapsize;
2924 qbyte *cubemappixels, *image_rgba;
2925 rtexture_t *cubemaptexture;
2927 // must start 0 so the first loadimagepixels has no requested width/height
2929 cubemappixels = NULL;
2930 cubemaptexture = NULL;
2931 // keep trying different suffix groups (posx, px, rt) until one loads
2932 for (j = 0;j < 3 && !cubemappixels;j++)
2934 // load the 6 images in the suffix group
2935 for (i = 0;i < 6;i++)
2937 // generate an image name based on the base and and suffix
2938 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2940 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2942 // an image loaded, make sure width and height are equal
2943 if (image_width == image_height)
2945 // if this is the first image to load successfully, allocate the cubemap memory
2946 if (!cubemappixels && image_width >= 1)
2948 cubemapsize = image_width;
2949 // note this clears to black, so unavailable sides are black
2950 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2952 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2954 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);
2957 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2959 Mem_Free(image_rgba);
2963 // if a cubemap loaded, upload it
2966 if (!r_shadow_filters_texturepool)
2967 r_shadow_filters_texturepool = R_AllocTexturePool();
2968 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2969 Mem_Free(cubemappixels);
2973 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2974 for (j = 0;j < 3;j++)
2975 for (i = 0;i < 6;i++)
2976 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2977 Con_Print(" and was unable to find any of them.\n");
2979 return cubemaptexture;
2982 rtexture_t *R_Shadow_Cubemap(const char *basename)
2985 for (i = 0;i < numcubemaps;i++)
2986 if (!strcasecmp(cubemaps[i].basename, basename))
2987 return cubemaps[i].texture;
2988 if (i >= MAX_CUBEMAPS)
2991 strcpy(cubemaps[i].basename, basename);
2992 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2993 return cubemaps[i].texture;
2996 void R_Shadow_FreeCubemaps(void)
2999 R_FreeTexturePool(&r_shadow_filters_texturepool);
3002 dlight_t *R_Shadow_NewWorldLight(void)
3005 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3006 light->next = r_shadow_worldlightchain;
3007 r_shadow_worldlightchain = light;
3011 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)
3013 VectorCopy(origin, light->origin);
3014 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3015 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3016 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3017 light->color[0] = max(color[0], 0);
3018 light->color[1] = max(color[1], 0);
3019 light->color[2] = max(color[2], 0);
3020 light->radius = max(radius, 0);
3021 light->style = style;
3022 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3024 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3027 light->shadow = shadowenable;
3028 light->corona = corona;
3031 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
3032 light->coronasizescale = coronasizescale;
3033 light->ambientscale = ambientscale;
3034 light->diffusescale = diffusescale;
3035 light->specularscale = specularscale;
3036 light->flags = flags;
3037 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3039 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3042 void R_Shadow_FreeWorldLight(dlight_t *light)
3044 dlight_t **lightpointer;
3045 R_RTLight_Uncompile(&light->rtlight);
3046 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3047 if (*lightpointer != light)
3048 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3049 *lightpointer = light->next;
3053 void R_Shadow_ClearWorldLights(void)
3055 while (r_shadow_worldlightchain)
3056 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3057 r_shadow_selectedlight = NULL;
3058 R_Shadow_FreeCubemaps();
3061 void R_Shadow_SelectLight(dlight_t *light)
3063 if (r_shadow_selectedlight)
3064 r_shadow_selectedlight->selected = false;
3065 r_shadow_selectedlight = light;
3066 if (r_shadow_selectedlight)
3067 r_shadow_selectedlight->selected = true;
3070 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3072 float scale = r_editlights_cursorgrid.value * 0.5f;
3073 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);
3076 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3079 const dlight_t *light;
3082 if (light->selected)
3083 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3086 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);
3089 void R_Shadow_DrawLightSprites(void)
3095 for (i = 0;i < 5;i++)
3097 lighttextures[i] = NULL;
3098 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3099 lighttextures[i] = pic->tex;
3102 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3103 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3104 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3107 void R_Shadow_SelectLightInView(void)
3109 float bestrating, rating, temp[3];
3110 dlight_t *best, *light;
3113 for (light = r_shadow_worldlightchain;light;light = light->next)
3115 VectorSubtract(light->origin, r_vieworigin, temp);
3116 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3119 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3120 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3122 bestrating = rating;
3127 R_Shadow_SelectLight(best);
3130 void R_Shadow_LoadWorldLights(void)
3132 int n, a, style, shadow, flags;
3133 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
3134 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3135 if (r_refdef.worldmodel == NULL)
3137 Con_Print("No map loaded.\n");
3140 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3141 strlcat (name, ".rtlights", sizeof (name));
3142 lightsstring = FS_LoadFile(name, tempmempool, false);
3152 for (;COM_Parse(t, true) && strcmp(
3153 if (COM_Parse(t, true))
3155 if (com_token[0] == '!')
3158 origin[0] = atof(com_token+1);
3161 origin[0] = atof(com_token);
3166 while (*s && *s != '\n')
3172 // check for modifier flags
3178 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);
3180 flags = LIGHTFLAG_REALTIMEMODE;
3188 coronasizescale = 0.25f;
3190 VectorClear(angles);
3193 if (a < 9 || !strcmp(cubemapname, "\"\""))
3195 // remove quotes on cubemapname
3196 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3198 cubemapname[strlen(cubemapname)-1] = 0;
3199 strcpy(cubemapname, cubemapname + 1);
3204 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);
3207 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3208 radius *= r_editlights_rtlightssizescale.value;
3209 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3214 Con_Printf("invalid rtlights file \"%s\"\n", name);
3215 Mem_Free(lightsstring);
3219 void R_Shadow_SaveWorldLights(void)
3222 int bufchars, bufmaxchars;
3224 char name[MAX_QPATH];
3226 if (!r_shadow_worldlightchain)
3228 if (r_refdef.worldmodel == NULL)
3230 Con_Print("No map loaded.\n");
3233 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3234 strlcat (name, ".rtlights", sizeof (name));
3235 bufchars = bufmaxchars = 0;
3237 for (light = r_shadow_worldlightchain;light;light = light->next)
3239 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3240 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);
3241 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3242 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]);
3244 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);
3245 if (bufchars + (int) strlen(line) > bufmaxchars)
3247 bufmaxchars = bufchars + strlen(line) + 2048;
3249 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3253 memcpy(buf, oldbuf, bufchars);
3259 memcpy(buf + bufchars, line, strlen(line));
3260 bufchars += strlen(line);
3264 FS_WriteFile(name, buf, bufchars);
3269 void R_Shadow_LoadLightsFile(void)
3272 char name[MAX_QPATH], *lightsstring, *s, *t;
3273 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3274 if (r_refdef.worldmodel == NULL)
3276 Con_Print("No map loaded.\n");
3279 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3280 strlcat (name, ".lights", sizeof (name));
3281 lightsstring = FS_LoadFile(name, tempmempool, false);
3289 while (*s && *s != '\n')
3294 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);
3298 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);
3301 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3302 radius = bound(15, radius, 4096);
3303 VectorScale(color, (2.0f / (8388608.0f)), color);
3304 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3309 Con_Printf("invalid lights file \"%s\"\n", name);
3310 Mem_Free(lightsstring);
3314 // tyrlite/hmap2 light types in the delay field
3315 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3317 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3319 int entnum, style, islight, skin, pflags, effects, type, n;
3322 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3323 char key[256], value[1024];
3325 if (r_refdef.worldmodel == NULL)
3327 Con_Print("No map loaded.\n");
3330 // try to load a .ent file first
3331 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3332 strlcat (key, ".ent", sizeof (key));
3333 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3334 // and if that is not found, fall back to the bsp file entity string
3336 data = r_refdef.worldmodel->brush.entities;
3339 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3341 type = LIGHTTYPE_MINUSX;
3342 origin[0] = origin[1] = origin[2] = 0;
3343 originhack[0] = originhack[1] = originhack[2] = 0;
3344 angles[0] = angles[1] = angles[2] = 0;
3345 color[0] = color[1] = color[2] = 1;
3346 light[0] = light[1] = light[2] = 1;light[3] = 300;
3347 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3357 if (!COM_ParseToken(&data, false))
3359 if (com_token[0] == '}')
3360 break; // end of entity
3361 if (com_token[0] == '_')
3362 strcpy(key, com_token + 1);
3364 strcpy(key, com_token);
3365 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3366 key[strlen(key)-1] = 0;
3367 if (!COM_ParseToken(&data, false))
3369 strcpy(value, com_token);
3371 // now that we have the key pair worked out...
3372 if (!strcmp("light", key))
3374 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3378 light[0] = vec[0] * (1.0f / 256.0f);
3379 light[1] = vec[0] * (1.0f / 256.0f);
3380 light[2] = vec[0] * (1.0f / 256.0f);
3386 light[0] = vec[0] * (1.0f / 255.0f);
3387 light[1] = vec[1] * (1.0f / 255.0f);
3388 light[2] = vec[2] * (1.0f / 255.0f);
3392 else if (!strcmp("delay", key))
3394 else if (!strcmp("origin", key))
3395 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3396 else if (!strcmp("angle", key))
3397 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3398 else if (!strcmp("angles", key))
3399 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3400 else if (!strcmp("color", key))
3401 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3402 else if (!strcmp("wait", key))
3403 fadescale = atof(value);
3404 else if (!strcmp("classname", key))
3406 if (!strncmp(value, "light", 5))
3409 if (!strcmp(value, "light_fluoro"))
3414 overridecolor[0] = 1;
3415 overridecolor[1] = 1;
3416 overridecolor[2] = 1;
3418 if (!strcmp(value, "light_fluorospark"))
3423 overridecolor[0] = 1;
3424 overridecolor[1] = 1;
3425 overridecolor[2] = 1;
3427 if (!strcmp(value, "light_globe"))
3432 overridecolor[0] = 1;
3433 overridecolor[1] = 0.8;
3434 overridecolor[2] = 0.4;
3436 if (!strcmp(value, "light_flame_large_yellow"))
3441 overridecolor[0] = 1;
3442 overridecolor[1] = 0.5;
3443 overridecolor[2] = 0.1;
3445 if (!strcmp(value, "light_flame_small_yellow"))
3450 overridecolor[0] = 1;
3451 overridecolor[1] = 0.5;
3452 overridecolor[2] = 0.1;
3454 if (!strcmp(value, "light_torch_small_white"))
3459 overridecolor[0] = 1;
3460 overridecolor[1] = 0.5;
3461 overridecolor[2] = 0.1;
3463 if (!strcmp(value, "light_torch_small_walltorch"))
3468 overridecolor[0] = 1;
3469 overridecolor[1] = 0.5;
3470 overridecolor[2] = 0.1;
3474 else if (!strcmp("style", key))
3475 style = atoi(value);
3476 else if (r_refdef.worldmodel->type == mod_brushq3)
3478 if (!strcmp("scale", key))
3479 lightscale = atof(value);
3480 if (!strcmp("fade", key))
3481 fadescale = atof(value);
3483 else if (!strcmp("skin", key))
3484 skin = (int)atof(value);
3485 else if (!strcmp("pflags", key))
3486 pflags = (int)atof(value);
3487 else if (!strcmp("effects", key))
3488 effects = (int)atof(value);
3492 if (lightscale <= 0)
3496 if (color[0] == color[1] && color[0] == color[2])
3498 color[0] *= overridecolor[0];
3499 color[1] *= overridecolor[1];
3500 color[2] *= overridecolor[2];
3502 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3503 color[0] = color[0] * light[0];
3504 color[1] = color[1] * light[1];
3505 color[2] = color[2] * light[2];
3508 case LIGHTTYPE_MINUSX:
3510 case LIGHTTYPE_RECIPX:
3512 VectorScale(color, (1.0f / 16.0f), color);
3514 case LIGHTTYPE_RECIPXX:
3516 VectorScale(color, (1.0f / 16.0f), color);
3519 case LIGHTTYPE_NONE:
3523 case LIGHTTYPE_MINUSXX:
3526 VectorAdd(origin, originhack, origin);
3528 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);
3531 Mem_Free(entfiledata);
3535 void R_Shadow_SetCursorLocationForView(void)
3537 vec_t dist, push, frac;
3538 vec3_t dest, endpos, normal;
3539 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3540 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3543 dist = frac * r_editlights_cursordistance.value;
3544 push = r_editlights_cursorpushback.value;
3548 VectorMA(endpos, push, r_viewforward, endpos);
3549 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3551 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3552 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3553 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3556 void R_Shadow_UpdateWorldLightSelection(void)
3558 if (r_editlights.integer)
3560 R_Shadow_SetCursorLocationForView();
3561 R_Shadow_SelectLightInView();
3562 R_Shadow_DrawLightSprites();
3565 R_Shadow_SelectLight(NULL);
3568 void R_Shadow_EditLights_Clear_f(void)
3570 R_Shadow_ClearWorldLights();
3573 void R_Shadow_EditLights_Reload_f(void)
3575 if (!r_refdef.worldmodel)
3577 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3578 R_Shadow_ClearWorldLights();
3579 R_Shadow_LoadWorldLights();
3580 if (r_shadow_worldlightchain == NULL)
3582 R_Shadow_LoadLightsFile();
3583 if (r_shadow_worldlightchain == NULL)
3584 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3588 void R_Shadow_EditLights_Save_f(void)
3590 if (!r_refdef.worldmodel)
3592 R_Shadow_SaveWorldLights();
3595 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3597 R_Shadow_ClearWorldLights();
3598 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3601 void R_Shadow_EditLights_ImportLightsFile_f(void)
3603 R_Shadow_ClearWorldLights();
3604 R_Shadow_LoadLightsFile();
3607 void R_Shadow_EditLights_Spawn_f(void)
3610 if (!r_editlights.integer)
3612 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3615 if (Cmd_Argc() != 1)
3617 Con_Print("r_editlights_spawn does not take parameters\n");
3620 color[0] = color[1] = color[2] = 1;
3621 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3624 void R_Shadow_EditLights_Edit_f(void)
3626 vec3_t origin, angles, color;
3627 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3628 int style, shadows, flags, normalmode, realtimemode;
3629 char cubemapname[1024];
3630 if (!r_editlights.integer)
3632 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3635 if (!r_shadow_selectedlight)
3637 Con_Print("No selected light.\n");
3640 VectorCopy(r_shadow_selectedlight->origin, origin);
3641 VectorCopy(r_shadow_selectedlight->angles, angles);
3642 VectorCopy(r_shadow_selectedlight->color, color);
3643 radius = r_shadow_selectedlight->radius;
3644 style = r_shadow_selectedlight->style;
3645 if (r_shadow_selectedlight->cubemapname)
3646 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3649 shadows = r_shadow_selectedlight->shadow;
3650 corona = r_shadow_selectedlight->corona;
3651 coronasizescale = r_shadow_selectedlight->coronasizescale;
3652 ambientscale = r_shadow_selectedlight->ambientscale;
3653 diffusescale = r_shadow_selectedlight->diffusescale;
3654 specularscale = r_shadow_selectedlight->specularscale;
3655 flags = r_shadow_selectedlight->flags;
3656 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3657 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3658 if (!strcmp(Cmd_Argv(1), "origin"))
3660 if (Cmd_Argc() != 5)
3662 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3665 origin[0] = atof(Cmd_Argv(2));
3666 origin[1] = atof(Cmd_Argv(3));
3667 origin[2] = atof(Cmd_Argv(4));
3669 else if (!strcmp(Cmd_Argv(1), "originx"))
3671 if (Cmd_Argc() != 3)
3673 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3676 origin[0] = atof(Cmd_Argv(2));
3678 else if (!strcmp(Cmd_Argv(1), "originy"))
3680 if (Cmd_Argc() != 3)
3682 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3685 origin[1] = atof(Cmd_Argv(2));
3687 else if (!strcmp(Cmd_Argv(1), "originz"))
3689 if (Cmd_Argc() != 3)
3691 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3694 origin[2] = atof(Cmd_Argv(2));
3696 else if (!strcmp(Cmd_Argv(1), "move"))
3698 if (Cmd_Argc() != 5)
3700 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3703 origin[0] += atof(Cmd_Argv(2));
3704 origin[1] += atof(Cmd_Argv(3));
3705 origin[2] += atof(Cmd_Argv(4));
3707 else if (!strcmp(Cmd_Argv(1), "movex"))
3709 if (Cmd_Argc() != 3)
3711 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3714 origin[0] += atof(Cmd_Argv(2));
3716 else if (!strcmp(Cmd_Argv(1), "movey"))
3718 if (Cmd_Argc() != 3)
3720 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3723 origin[1] += atof(Cmd_Argv(2));
3725 else if (!strcmp(Cmd_Argv(1), "movez"))
3727 if (Cmd_Argc() != 3)
3729 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3732 origin[2] += atof(Cmd_Argv(2));
3734 else if (!strcmp(Cmd_Argv(1), "angles"))
3736 if (Cmd_Argc() != 5)
3738 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3741 angles[0] = atof(Cmd_Argv(2));
3742 angles[1] = atof(Cmd_Argv(3));
3743 angles[2] = atof(Cmd_Argv(4));
3745 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3747 if (Cmd_Argc() != 3)
3749 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3752 angles[0] = atof(Cmd_Argv(2));
3754 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3756 if (Cmd_Argc() != 3)
3758 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3761 angles[1] = atof(Cmd_Argv(2));
3763 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3765 if (Cmd_Argc() != 3)
3767 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3770 angles[2] = atof(Cmd_Argv(2));
3772 else if (!strcmp(Cmd_Argv(1), "color"))
3774 if (Cmd_Argc() != 5)
3776 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3779 color[0] = atof(Cmd_Argv(2));
3780 color[1] = atof(Cmd_Argv(3));
3781 color[2] = atof(Cmd_Argv(4));
3783 else if (!strcmp(Cmd_Argv(1), "radius"))
3785 if (Cmd_Argc() != 3)
3787 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3790 radius = atof(Cmd_Argv(2));
3792 else if (!strcmp(Cmd_Argv(1), "style"))
3794 if (Cmd_Argc() != 3)
3796 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3799 style = atoi(Cmd_Argv(2));
3801 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3805 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3808 if (Cmd_Argc() == 3)
3809 strcpy(cubemapname, Cmd_Argv(2));
3813 else if (!strcmp(Cmd_Argv(1), "shadows"))
3815 if (Cmd_Argc() != 3)
3817 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3820 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3822 else if (!strcmp(Cmd_Argv(1), "corona"))
3824 if (Cmd_Argc() != 3)
3826 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3829 corona = atof(Cmd_Argv(2));
3831 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3833 if (Cmd_Argc() != 3)
3835 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3838 coronasizescale = atof(Cmd_Argv(2));
3840 else if (!strcmp(Cmd_Argv(1), "ambient"))
3842 if (Cmd_Argc() != 3)
3844 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3847 ambientscale = atof(Cmd_Argv(2));
3849 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3851 if (Cmd_Argc() != 3)
3853 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3856 diffusescale = atof(Cmd_Argv(2));
3858 else if (!strcmp(Cmd_Argv(1), "specular"))
3860 if (Cmd_Argc() != 3)
3862 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3865 specularscale = atof(Cmd_Argv(2));
3867 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3869 if (Cmd_Argc() != 3)
3871 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3874 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3876 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3878 if (Cmd_Argc() != 3)
3880 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3883 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3887 Con_Print("usage: r_editlights_edit [property] [value]\n");
3888 Con_Print("Selected light's properties:\n");
3889 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3890 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3891 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3892 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3893 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3894 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3895 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3896 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3897 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3898 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3899 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3900 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3901 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3902 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3905 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3906 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3909 void R_Shadow_EditLights_EditAll_f(void)
3913 if (!r_editlights.integer)
3915 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3919 for (light = r_shadow_worldlightchain;light;light = light->next)
3921 R_Shadow_SelectLight(light);
3922 R_Shadow_EditLights_Edit_f();
3926 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3928 int lightnumber, lightcount;
3932 if (!r_editlights.integer)
3938 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3939 if (light == r_shadow_selectedlight)
3940 lightnumber = lightcount;
3941 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;
3942 if (r_shadow_selectedlight == NULL)
3944 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3945 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;
3946 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;
3947 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;
3948 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3949 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3950 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3951 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;
3952 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3953 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3954 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3955 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3956 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3957 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;
3958 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;
3961 void R_Shadow_EditLights_ToggleShadow_f(void)
3963 if (!r_editlights.integer)
3965 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3968 if (!r_shadow_selectedlight)
3970 Con_Print("No selected light.\n");
3973 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);
3976 void R_Shadow_EditLights_ToggleCorona_f(void)
3978 if (!r_editlights.integer)
3980 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3983 if (!r_shadow_selectedlight)
3985 Con_Print("No selected light.\n");
3988 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);
3991 void R_Shadow_EditLights_Remove_f(void)
3993 if (!r_editlights.integer)
3995 Con_Print("Cannot remove 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_FreeWorldLight(r_shadow_selectedlight);
4004 r_shadow_selectedlight = NULL;
4007 void R_Shadow_EditLights_Help_f(void)
4010 "Documentation on r_editlights system:\n"
4012 "r_editlights : enable/disable editing mode\n"
4013 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4014 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4015 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4016 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4017 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4018 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4019 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4021 "r_editlights_help : this help\n"
4022 "r_editlights_clear : remove all lights\n"
4023 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4024 "r_editlights_save : save to .rtlights file\n"
4025 "r_editlights_spawn : create a light with default settings\n"
4026 "r_editlights_edit command : edit selected light - more documentation below\n"
4027 "r_editlights_remove : remove selected light\n"
4028 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4029 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4030 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4032 "origin x y z : set light location\n"
4033 "originx x: set x component of light location\n"
4034 "originy y: set y component of light location\n"
4035 "originz z: set z component of light location\n"
4036 "move x y z : adjust light location\n"
4037 "movex x: adjust x component of light location\n"
4038 "movey y: adjust y component of light location\n"
4039 "movez z: adjust z component of light location\n"
4040 "angles x y z : set light angles\n"
4041 "anglesx x: set x component of light angles\n"
4042 "anglesy y: set y component of light angles\n"
4043 "anglesz z: set z component of light angles\n"
4044 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4045 "radius radius : set radius (size) of light\n"
4046 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4047 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4048 "shadows 1/0 : turn on/off shadows\n"
4049 "corona n : set corona intensity\n"
4050 "coronasize n : set corona size (0-1)\n"
4051 "ambient n : set ambient intensity (0-1)\n"
4052 "diffuse n : set diffuse intensity (0-1)\n"
4053 "specular n : set specular intensity (0-1)\n"
4054 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4055 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4056 "<nothing> : print light properties to console\n"
4060 void R_Shadow_EditLights_CopyInfo_f(void)
4062 if (!r_editlights.integer)
4064 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4067 if (!r_shadow_selectedlight)
4069 Con_Print("No selected light.\n");
4072 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4073 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4074 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4075 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4076 if (r_shadow_selectedlight->cubemapname)
4077 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4079 r_shadow_bufferlight.cubemapname[0] = 0;
4080 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4081 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4082 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4083 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4084 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4085 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4086 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4089 void R_Shadow_EditLights_PasteInfo_f(void)
4091 if (!r_editlights.integer)
4093 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4096 if (!r_shadow_selectedlight)
4098 Con_Print("No selected light.\n");
4101 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);
4104 void R_Shadow_EditLights_Init(void)
4106 Cvar_RegisterVariable(&r_editlights);
4107 Cvar_RegisterVariable(&r_editlights_cursordistance);
4108 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4109 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4110 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4111 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4112 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4113 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4114 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4115 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4116 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4117 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4118 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4119 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4120 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4121 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4122 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4123 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4124 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4125 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4126 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4127 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);