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);
1662 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1663 qglBegin(GL_TRIANGLES);
1666 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1669 bumptexture = r_shadow_blankbumptexture;
1671 glosstexture = r_shadow_blankglosstexture;
1675 colorscale = ambientscale;
1676 // colorscale accounts for how much we multiply the brightness
1679 // mult is how many times the final pass of the lighting will be
1680 // performed to get more brightness than otherwise possible.
1682 // Limit mult to 64 for sanity sake.
1683 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1685 // 3 3D combine path (Geforce3, Radeon 8500)
1686 memset(&m, 0, sizeof(m));
1687 m.pointer_vertex = vertex3f;
1688 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1690 m.pointer_texcoord3f[0] = vertex3f;
1691 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1693 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1694 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1696 m.tex[1] = R_GetTexture(basetexture);
1697 m.pointer_texcoord[1] = texcoord2f;
1698 m.texcubemap[2] = R_GetTexture(lightcubemap);
1700 m.pointer_texcoord3f[2] = vertex3f;
1701 m.texmatrix[2] = *matrix_modeltolight;
1703 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1704 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1706 GL_BlendFunc(GL_ONE, GL_ONE);
1708 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1710 // 2 3D combine path (Geforce3, original Radeon)
1711 memset(&m, 0, sizeof(m));
1712 m.pointer_vertex = vertex3f;
1713 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1715 m.pointer_texcoord3f[0] = vertex3f;
1716 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1718 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1719 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1721 m.tex[1] = R_GetTexture(basetexture);
1722 m.pointer_texcoord[1] = texcoord2f;
1723 GL_BlendFunc(GL_ONE, GL_ONE);
1725 else if (r_textureunits.integer >= 4 && lightcubemap)
1727 // 4 2D combine path (Geforce3, Radeon 8500)
1728 memset(&m, 0, sizeof(m));
1729 m.pointer_vertex = vertex3f;
1730 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1732 m.pointer_texcoord3f[0] = vertex3f;
1733 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1735 m.pointer_texcoord[0] = varray_texcoord2f[0];
1736 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1738 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1740 m.pointer_texcoord3f[1] = vertex3f;
1741 m.texmatrix[1] = *matrix_modeltoattenuationz;
1743 m.pointer_texcoord[1] = varray_texcoord2f[1];
1744 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1746 m.tex[2] = R_GetTexture(basetexture);
1747 m.pointer_texcoord[2] = texcoord2f;
1750 m.texcubemap[3] = R_GetTexture(lightcubemap);
1752 m.pointer_texcoord3f[3] = vertex3f;
1753 m.texmatrix[3] = *matrix_modeltolight;
1755 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1756 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1759 GL_BlendFunc(GL_ONE, GL_ONE);
1761 else if (r_textureunits.integer >= 3 && !lightcubemap)
1763 // 3 2D combine path (Geforce3, original Radeon)
1764 memset(&m, 0, sizeof(m));
1765 m.pointer_vertex = vertex3f;
1766 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1768 m.pointer_texcoord3f[0] = vertex3f;
1769 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1771 m.pointer_texcoord[0] = varray_texcoord2f[0];
1772 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1774 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1776 m.pointer_texcoord3f[1] = vertex3f;
1777 m.texmatrix[1] = *matrix_modeltoattenuationz;
1779 m.pointer_texcoord[1] = varray_texcoord2f[1];
1780 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1782 m.tex[2] = R_GetTexture(basetexture);
1783 m.pointer_texcoord[2] = texcoord2f;
1784 GL_BlendFunc(GL_ONE, GL_ONE);
1788 // 2/2/2 2D combine path (any dot3 card)
1789 memset(&m, 0, sizeof(m));
1790 m.pointer_vertex = vertex3f;
1791 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1793 m.pointer_texcoord3f[0] = vertex3f;
1794 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1796 m.pointer_texcoord[0] = varray_texcoord2f[0];
1797 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1799 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1801 m.pointer_texcoord3f[1] = vertex3f;
1802 m.texmatrix[1] = *matrix_modeltoattenuationz;
1804 m.pointer_texcoord[1] = varray_texcoord2f[1];
1805 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1808 GL_ColorMask(0,0,0,1);
1809 GL_BlendFunc(GL_ONE, GL_ZERO);
1810 GL_LockArrays(0, numverts);
1811 R_Mesh_Draw(numverts, numtriangles, elements);
1812 GL_LockArrays(0, 0);
1814 c_rt_lighttris += numtriangles;
1816 memset(&m, 0, sizeof(m));
1817 m.pointer_vertex = vertex3f;
1818 m.tex[0] = R_GetTexture(basetexture);
1819 m.pointer_texcoord[0] = texcoord2f;
1822 m.texcubemap[1] = R_GetTexture(lightcubemap);
1824 m.pointer_texcoord3f[1] = vertex3f;
1825 m.texmatrix[1] = *matrix_modeltolight;
1827 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1828 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1831 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1833 // this final code is shared
1835 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1836 VectorScale(lightcolor, colorscale, color2);
1837 GL_LockArrays(0, numverts);
1838 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1840 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1841 R_Mesh_Draw(numverts, numtriangles, elements);
1843 c_rt_lighttris += numtriangles;
1845 GL_LockArrays(0, 0);
1850 colorscale = diffusescale;
1851 // colorscale accounts for how much we multiply the brightness
1854 // mult is how many times the final pass of the lighting will be
1855 // performed to get more brightness than otherwise possible.
1857 // Limit mult to 64 for sanity sake.
1858 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1860 // 3/2 3D combine path (Geforce3, Radeon 8500)
1861 memset(&m, 0, sizeof(m));
1862 m.pointer_vertex = vertex3f;
1863 m.tex[0] = R_GetTexture(bumptexture);
1864 m.texcombinergb[0] = GL_REPLACE;
1865 m.pointer_texcoord[0] = texcoord2f;
1866 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1867 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1868 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1869 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1870 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1872 m.pointer_texcoord3f[2] = vertex3f;
1873 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1875 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1876 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1879 GL_ColorMask(0,0,0,1);
1880 GL_BlendFunc(GL_ONE, GL_ZERO);
1881 GL_LockArrays(0, numverts);
1882 R_Mesh_Draw(numverts, numtriangles, elements);
1883 GL_LockArrays(0, 0);
1885 c_rt_lighttris += numtriangles;
1887 memset(&m, 0, sizeof(m));
1888 m.pointer_vertex = vertex3f;
1889 m.tex[0] = R_GetTexture(basetexture);
1890 m.pointer_texcoord[0] = texcoord2f;
1893 m.texcubemap[1] = R_GetTexture(lightcubemap);
1895 m.pointer_texcoord3f[1] = vertex3f;
1896 m.texmatrix[1] = *matrix_modeltolight;
1898 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1899 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1902 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1904 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1906 // 1/2/2 3D combine path (original Radeon)
1907 memset(&m, 0, sizeof(m));
1908 m.pointer_vertex = vertex3f;
1909 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1911 m.pointer_texcoord3f[0] = vertex3f;
1912 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1914 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1915 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1918 GL_ColorMask(0,0,0,1);
1919 GL_BlendFunc(GL_ONE, GL_ZERO);
1920 GL_LockArrays(0, numverts);
1921 R_Mesh_Draw(numverts, numtriangles, elements);
1922 GL_LockArrays(0, 0);
1924 c_rt_lighttris += numtriangles;
1926 memset(&m, 0, sizeof(m));
1927 m.pointer_vertex = vertex3f;
1928 m.tex[0] = R_GetTexture(bumptexture);
1929 m.texcombinergb[0] = GL_REPLACE;
1930 m.pointer_texcoord[0] = texcoord2f;
1931 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1932 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1933 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1934 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1936 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1937 GL_LockArrays(0, numverts);
1938 R_Mesh_Draw(numverts, numtriangles, elements);
1939 GL_LockArrays(0, 0);
1941 c_rt_lighttris += numtriangles;
1943 memset(&m, 0, sizeof(m));
1944 m.pointer_vertex = vertex3f;
1945 m.tex[0] = R_GetTexture(basetexture);
1946 m.pointer_texcoord[0] = texcoord2f;
1949 m.texcubemap[1] = R_GetTexture(lightcubemap);
1951 m.pointer_texcoord3f[1] = vertex3f;
1952 m.texmatrix[1] = *matrix_modeltolight;
1954 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1955 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1958 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1960 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1962 // 2/2 3D combine path (original Radeon)
1963 memset(&m, 0, sizeof(m));
1964 m.pointer_vertex = vertex3f;
1965 m.tex[0] = R_GetTexture(bumptexture);
1966 m.texcombinergb[0] = GL_REPLACE;
1967 m.pointer_texcoord[0] = texcoord2f;
1968 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1969 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1970 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1971 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1973 GL_ColorMask(0,0,0,1);
1974 GL_BlendFunc(GL_ONE, GL_ZERO);
1975 GL_LockArrays(0, numverts);
1976 R_Mesh_Draw(numverts, numtriangles, elements);
1977 GL_LockArrays(0, 0);
1979 c_rt_lighttris += numtriangles;
1981 memset(&m, 0, sizeof(m));
1982 m.pointer_vertex = vertex3f;
1983 m.tex[0] = R_GetTexture(basetexture);
1984 m.pointer_texcoord[0] = texcoord2f;
1985 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1987 m.pointer_texcoord3f[1] = vertex3f;
1988 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1990 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1991 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1993 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1995 else if (r_textureunits.integer >= 4)
1997 // 4/2 2D combine path (Geforce3, Radeon 8500)
1998 memset(&m, 0, sizeof(m));
1999 m.pointer_vertex = vertex3f;
2000 m.tex[0] = R_GetTexture(bumptexture);
2001 m.texcombinergb[0] = GL_REPLACE;
2002 m.pointer_texcoord[0] = texcoord2f;
2003 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2004 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2005 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2006 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2007 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2009 m.pointer_texcoord3f[2] = vertex3f;
2010 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2012 m.pointer_texcoord[2] = varray_texcoord2f[2];
2013 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2015 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2017 m.pointer_texcoord3f[3] = vertex3f;
2018 m.texmatrix[3] = *matrix_modeltoattenuationz;
2020 m.pointer_texcoord[3] = varray_texcoord2f[3];
2021 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2024 GL_ColorMask(0,0,0,1);
2025 GL_BlendFunc(GL_ONE, GL_ZERO);
2026 GL_LockArrays(0, numverts);
2027 R_Mesh_Draw(numverts, numtriangles, elements);
2028 GL_LockArrays(0, 0);
2030 c_rt_lighttris += numtriangles;
2032 memset(&m, 0, sizeof(m));
2033 m.pointer_vertex = vertex3f;
2034 m.tex[0] = R_GetTexture(basetexture);
2035 m.pointer_texcoord[0] = texcoord2f;
2038 m.texcubemap[1] = R_GetTexture(lightcubemap);
2040 m.pointer_texcoord3f[1] = vertex3f;
2041 m.texmatrix[1] = *matrix_modeltolight;
2043 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2044 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2047 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2051 // 2/2/2 2D combine path (any dot3 card)
2052 memset(&m, 0, sizeof(m));
2053 m.pointer_vertex = vertex3f;
2054 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2056 m.pointer_texcoord3f[0] = vertex3f;
2057 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2059 m.pointer_texcoord[0] = varray_texcoord2f[0];
2060 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2062 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2064 m.pointer_texcoord3f[1] = vertex3f;
2065 m.texmatrix[1] = *matrix_modeltoattenuationz;
2067 m.pointer_texcoord[1] = varray_texcoord2f[1];
2068 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2071 GL_ColorMask(0,0,0,1);
2072 GL_BlendFunc(GL_ONE, GL_ZERO);
2073 GL_LockArrays(0, numverts);
2074 R_Mesh_Draw(numverts, numtriangles, elements);
2075 GL_LockArrays(0, 0);
2077 c_rt_lighttris += numtriangles;
2079 memset(&m, 0, sizeof(m));
2080 m.pointer_vertex = vertex3f;
2081 m.tex[0] = R_GetTexture(bumptexture);
2082 m.texcombinergb[0] = GL_REPLACE;
2083 m.pointer_texcoord[0] = texcoord2f;
2084 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2085 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2086 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2087 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2089 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2090 GL_LockArrays(0, numverts);
2091 R_Mesh_Draw(numverts, numtriangles, elements);
2092 GL_LockArrays(0, 0);
2094 c_rt_lighttris += numtriangles;
2096 memset(&m, 0, sizeof(m));
2097 m.pointer_vertex = vertex3f;
2098 m.tex[0] = R_GetTexture(basetexture);
2099 m.pointer_texcoord[0] = texcoord2f;
2102 m.texcubemap[1] = R_GetTexture(lightcubemap);
2104 m.pointer_texcoord3f[1] = vertex3f;
2105 m.texmatrix[1] = *matrix_modeltolight;
2107 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2108 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2111 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2113 // this final code is shared
2115 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2116 VectorScale(lightcolor, colorscale, color2);
2117 GL_LockArrays(0, numverts);
2118 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2120 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2121 R_Mesh_Draw(numverts, numtriangles, elements);
2123 c_rt_lighttris += numtriangles;
2125 GL_LockArrays(0, 0);
2127 if (specularscale && glosstexture != r_shadow_blankblacktexture)
2129 // FIXME: detect blendsquare!
2130 //if (gl_support_blendsquare)
2132 colorscale = specularscale;
2134 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2136 // 2/0/0/1/2 3D combine blendsquare path
2137 memset(&m, 0, sizeof(m));
2138 m.pointer_vertex = vertex3f;
2139 m.tex[0] = R_GetTexture(bumptexture);
2140 m.pointer_texcoord[0] = texcoord2f;
2141 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2142 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2143 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2144 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2146 GL_ColorMask(0,0,0,1);
2147 // this squares the result
2148 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2149 GL_LockArrays(0, numverts);
2150 R_Mesh_Draw(numverts, numtriangles, elements);
2151 GL_LockArrays(0, 0);
2153 c_rt_lighttris += numtriangles;
2155 memset(&m, 0, sizeof(m));
2156 m.pointer_vertex = vertex3f;
2158 GL_LockArrays(0, numverts);
2159 // square alpha in framebuffer a few times to make it shiny
2160 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2161 // these comments are a test run through this math for intensity 0.5
2162 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2163 // 0.25 * 0.25 = 0.0625 (this is another pass)
2164 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2165 R_Mesh_Draw(numverts, numtriangles, elements);
2167 c_rt_lighttris += numtriangles;
2168 R_Mesh_Draw(numverts, numtriangles, elements);
2170 c_rt_lighttris += numtriangles;
2171 GL_LockArrays(0, 0);
2173 memset(&m, 0, sizeof(m));
2174 m.pointer_vertex = vertex3f;
2175 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2177 m.pointer_texcoord3f[0] = vertex3f;
2178 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2180 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2181 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2184 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2185 GL_LockArrays(0, numverts);
2186 R_Mesh_Draw(numverts, numtriangles, elements);
2187 GL_LockArrays(0, 0);
2189 c_rt_lighttris += numtriangles;
2191 memset(&m, 0, sizeof(m));
2192 m.pointer_vertex = vertex3f;
2193 m.tex[0] = R_GetTexture(glosstexture);
2194 m.pointer_texcoord[0] = texcoord2f;
2197 m.texcubemap[1] = R_GetTexture(lightcubemap);
2199 m.pointer_texcoord3f[1] = vertex3f;
2200 m.texmatrix[1] = *matrix_modeltolight;
2202 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2203 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2206 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2208 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2210 // 2/0/0/2 3D combine blendsquare path
2211 memset(&m, 0, sizeof(m));
2212 m.pointer_vertex = vertex3f;
2213 m.tex[0] = R_GetTexture(bumptexture);
2214 m.pointer_texcoord[0] = texcoord2f;
2215 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2216 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2217 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2218 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2220 GL_ColorMask(0,0,0,1);
2221 // this squares the result
2222 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2223 GL_LockArrays(0, numverts);
2224 R_Mesh_Draw(numverts, numtriangles, elements);
2225 GL_LockArrays(0, 0);
2227 c_rt_lighttris += numtriangles;
2229 memset(&m, 0, sizeof(m));
2230 m.pointer_vertex = vertex3f;
2232 GL_LockArrays(0, numverts);
2233 // square alpha in framebuffer a few times to make it shiny
2234 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2235 // these comments are a test run through this math for intensity 0.5
2236 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2237 // 0.25 * 0.25 = 0.0625 (this is another pass)
2238 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2239 R_Mesh_Draw(numverts, numtriangles, elements);
2241 c_rt_lighttris += numtriangles;
2242 R_Mesh_Draw(numverts, numtriangles, elements);
2244 c_rt_lighttris += numtriangles;
2245 GL_LockArrays(0, 0);
2247 memset(&m, 0, sizeof(m));
2248 m.pointer_vertex = vertex3f;
2249 m.tex[0] = R_GetTexture(glosstexture);
2250 m.pointer_texcoord[0] = texcoord2f;
2251 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2253 m.pointer_texcoord3f[1] = vertex3f;
2254 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2256 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2257 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2259 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2263 // 2/0/0/2/2 2D combine blendsquare path
2264 memset(&m, 0, sizeof(m));
2265 m.pointer_vertex = vertex3f;
2266 m.tex[0] = R_GetTexture(bumptexture);
2267 m.pointer_texcoord[0] = texcoord2f;
2268 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2269 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2270 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2271 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2273 GL_ColorMask(0,0,0,1);
2274 // this squares the result
2275 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2276 GL_LockArrays(0, numverts);
2277 R_Mesh_Draw(numverts, numtriangles, elements);
2278 GL_LockArrays(0, 0);
2280 c_rt_lighttris += numtriangles;
2282 memset(&m, 0, sizeof(m));
2283 m.pointer_vertex = vertex3f;
2285 GL_LockArrays(0, numverts);
2286 // square alpha in framebuffer a few times to make it shiny
2287 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2288 // these comments are a test run through this math for intensity 0.5
2289 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2290 // 0.25 * 0.25 = 0.0625 (this is another pass)
2291 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2292 R_Mesh_Draw(numverts, numtriangles, elements);
2294 c_rt_lighttris += numtriangles;
2295 R_Mesh_Draw(numverts, numtriangles, elements);
2297 c_rt_lighttris += numtriangles;
2298 GL_LockArrays(0, 0);
2300 memset(&m, 0, sizeof(m));
2301 m.pointer_vertex = vertex3f;
2302 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2304 m.pointer_texcoord3f[0] = vertex3f;
2305 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2307 m.pointer_texcoord[0] = varray_texcoord2f[0];
2308 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2310 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2312 m.pointer_texcoord3f[1] = vertex3f;
2313 m.texmatrix[1] = *matrix_modeltoattenuationz;
2315 m.pointer_texcoord[1] = varray_texcoord2f[1];
2316 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2319 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2320 GL_LockArrays(0, numverts);
2321 R_Mesh_Draw(numverts, numtriangles, elements);
2322 GL_LockArrays(0, 0);
2324 c_rt_lighttris += numtriangles;
2326 memset(&m, 0, sizeof(m));
2327 m.pointer_vertex = vertex3f;
2328 m.tex[0] = R_GetTexture(glosstexture);
2329 m.pointer_texcoord[0] = texcoord2f;
2332 m.texcubemap[1] = R_GetTexture(lightcubemap);
2334 m.pointer_texcoord3f[1] = vertex3f;
2335 m.texmatrix[1] = *matrix_modeltolight;
2337 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2338 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2341 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2344 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2345 VectorScale(lightcolor, colorscale, color2);
2346 GL_LockArrays(0, numverts);
2347 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2349 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2350 R_Mesh_Draw(numverts, numtriangles, elements);
2352 c_rt_lighttris += numtriangles;
2354 GL_LockArrays(0, 0);
2362 GL_BlendFunc(GL_ONE, GL_ONE);
2363 VectorScale(lightcolor, ambientscale, color2);
2364 memset(&m, 0, sizeof(m));
2365 m.pointer_vertex = vertex3f;
2366 m.tex[0] = R_GetTexture(basetexture);
2367 m.pointer_texcoord[0] = texcoord2f;
2368 if (r_textureunits.integer >= 2)
2371 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2373 m.pointer_texcoord3f[1] = vertex3f;
2374 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2376 m.pointer_texcoord[1] = varray_texcoord2f[1];
2377 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2379 if (r_textureunits.integer >= 3)
2381 // Geforce3/Radeon class but not using dot3
2382 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2384 m.pointer_texcoord3f[2] = vertex3f;
2385 m.texmatrix[2] = *matrix_modeltoattenuationz;
2387 m.pointer_texcoord[2] = varray_texcoord2f[2];
2388 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2392 if (r_textureunits.integer >= 3)
2393 m.pointer_color = NULL;
2395 m.pointer_color = varray_color4f;
2397 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2399 color[0] = bound(0, color2[0], 1);
2400 color[1] = bound(0, color2[1], 1);
2401 color[2] = bound(0, color2[2], 1);
2402 if (r_textureunits.integer >= 3)
2403 GL_Color(color[0], color[1], color[2], 1);
2404 else if (r_textureunits.integer >= 2)
2405 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2407 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2408 GL_LockArrays(0, numverts);
2409 R_Mesh_Draw(numverts, numtriangles, elements);
2410 GL_LockArrays(0, 0);
2412 c_rt_lighttris += numtriangles;
2417 GL_BlendFunc(GL_ONE, GL_ONE);
2418 VectorScale(lightcolor, diffusescale, color2);
2419 memset(&m, 0, sizeof(m));
2420 m.pointer_vertex = vertex3f;
2421 m.pointer_color = varray_color4f;
2422 m.tex[0] = R_GetTexture(basetexture);
2423 m.pointer_texcoord[0] = texcoord2f;
2424 if (r_textureunits.integer >= 2)
2427 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2429 m.pointer_texcoord3f[1] = vertex3f;
2430 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2432 m.pointer_texcoord[1] = varray_texcoord2f[1];
2433 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2435 if (r_textureunits.integer >= 3)
2437 // Geforce3/Radeon class but not using dot3
2438 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2440 m.pointer_texcoord3f[2] = vertex3f;
2441 m.texmatrix[2] = *matrix_modeltoattenuationz;
2443 m.pointer_texcoord[2] = varray_texcoord2f[2];
2444 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2449 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2451 color[0] = bound(0, color2[0], 1);
2452 color[1] = bound(0, color2[1], 1);
2453 color[2] = bound(0, color2[2], 1);
2454 if (r_textureunits.integer >= 3)
2455 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2456 else if (r_textureunits.integer >= 2)
2457 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2459 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2460 GL_LockArrays(0, numverts);
2461 R_Mesh_Draw(numverts, numtriangles, elements);
2462 GL_LockArrays(0, 0);
2464 c_rt_lighttris += numtriangles;
2470 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2474 R_RTLight_Uncompile(rtlight);
2475 memset(rtlight, 0, sizeof(*rtlight));
2477 VectorCopy(light->origin, rtlight->shadoworigin);
2478 VectorCopy(light->color, rtlight->color);
2479 rtlight->radius = light->radius;
2480 //rtlight->cullradius = rtlight->radius;
2481 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2482 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2483 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2484 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2485 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2486 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2487 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2488 rtlight->cubemapname[0] = 0;
2489 if (light->cubemapname[0])
2490 strcpy(rtlight->cubemapname, light->cubemapname);
2491 else if (light->cubemapnum > 0)
2492 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2493 rtlight->shadow = light->shadow;
2494 rtlight->corona = light->corona;
2495 rtlight->style = light->style;
2496 rtlight->isstatic = isstatic;
2497 rtlight->coronasizescale = light->coronasizescale;
2498 rtlight->ambientscale = light->ambientscale;
2499 rtlight->diffusescale = light->diffusescale;
2500 rtlight->specularscale = light->specularscale;
2501 rtlight->flags = light->flags;
2502 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2503 // ConcatScale won't work here because this needs to scale rotate and
2504 // translate, not just rotate
2505 scale = 1.0f / rtlight->radius;
2506 for (k = 0;k < 3;k++)
2507 for (j = 0;j < 4;j++)
2508 rtlight->matrix_worldtolight.m[k][j] *= scale;
2509 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2510 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2512 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2513 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2514 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2515 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2518 // compiles rtlight geometry
2519 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2520 void R_RTLight_Compile(rtlight_t *rtlight)
2522 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2523 entity_render_t *ent = &cl_entities[0].render;
2524 model_t *model = ent->model;
2526 // compile the light
2527 rtlight->compiled = true;
2528 rtlight->static_numclusters = 0;
2529 rtlight->static_numclusterpvsbytes = 0;
2530 rtlight->static_clusterlist = NULL;
2531 rtlight->static_clusterpvs = NULL;
2532 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2533 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2534 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2535 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2536 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2537 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2539 if (model && model->GetLightInfo)
2541 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2542 r_shadow_compilingrtlight = rtlight;
2543 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2544 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2545 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);
2546 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2547 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2550 rtlight->static_numclusters = numclusters;
2551 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2552 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2553 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2555 if (model->DrawShadowVolume && rtlight->shadow)
2557 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2558 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2559 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2561 if (model->DrawLight)
2563 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2564 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);
2565 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2567 // switch back to rendering when DrawShadowVolume or DrawLight is called
2568 r_shadow_compilingrtlight = NULL;
2572 // use smallest available cullradius - box radius or light radius
2573 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2574 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2578 if (rtlight->static_meshchain_shadow)
2581 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2584 shadowtris += mesh->numtriangles;
2590 if (rtlight->static_meshchain_light)
2593 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2596 lighttris += mesh->numtriangles;
2600 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);
2603 void R_RTLight_Uncompile(rtlight_t *rtlight)
2605 if (rtlight->compiled)
2607 if (rtlight->static_meshchain_shadow)
2608 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2609 rtlight->static_meshchain_shadow = NULL;
2610 if (rtlight->static_meshchain_light)
2611 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2612 rtlight->static_meshchain_light = NULL;
2613 if (rtlight->static_clusterlist)
2614 Mem_Free(rtlight->static_clusterlist);
2615 rtlight->static_clusterlist = NULL;
2616 if (rtlight->static_clusterpvs)
2617 Mem_Free(rtlight->static_clusterpvs);
2618 rtlight->static_clusterpvs = NULL;
2619 rtlight->static_numclusters = 0;
2620 rtlight->static_numclusterpvsbytes = 0;
2621 rtlight->compiled = false;
2625 void R_Shadow_UncompileWorldLights(void)
2628 for (light = r_shadow_worldlightchain;light;light = light->next)
2629 R_RTLight_Uncompile(&light->rtlight);
2632 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2634 int i, shadow, usestencil;
2635 entity_render_t *ent;
2637 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2638 rtexture_t *cubemaptexture;
2639 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2640 int numclusters, numsurfaces;
2641 int *clusterlist, *surfacelist;
2643 vec3_t cullmins, cullmaxs;
2647 // skip lights that don't light (corona only lights)
2648 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2651 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2652 VectorScale(rtlight->color, f, lightcolor);
2653 if (VectorLength2(lightcolor) < 0.01)
2656 if (rtlight->selected)
2658 f = 2 + sin(realtime * M_PI * 4.0);
2659 VectorScale(lightcolor, f, lightcolor);
2663 // loading is done before visibility checks because loading should happen
2664 // all at once at the start of a level, not when it stalls gameplay.
2665 // (especially important to benchmarks)
2666 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2667 R_RTLight_Compile(rtlight);
2668 if (rtlight->cubemapname[0])
2669 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2671 cubemaptexture = NULL;
2673 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2674 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2675 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2676 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2677 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2678 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2679 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2686 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2688 // compiled light, world available and can receive realtime lighting
2689 // retrieve cluster information
2690 numclusters = rtlight->static_numclusters;
2691 clusterlist = rtlight->static_clusterlist;
2692 clusterpvs = rtlight->static_clusterpvs;
2693 VectorCopy(rtlight->cullmins, cullmins);
2694 VectorCopy(rtlight->cullmaxs, cullmaxs);
2696 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2698 // dynamic light, world available and can receive realtime lighting
2699 // if the light box is offscreen, skip it right away
2700 if (R_CullBox(cullmins, cullmaxs))
2702 // calculate lit surfaces and clusters
2703 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2704 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2705 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);
2706 clusterlist = r_shadow_buffer_clusterlist;
2707 clusterpvs = r_shadow_buffer_clusterpvs;
2708 surfacelist = r_shadow_buffer_surfacelist;
2710 // if the reduced cluster bounds are offscreen, skip it
2711 if (R_CullBox(cullmins, cullmaxs))
2713 // check if light is illuminating any visible clusters
2716 for (i = 0;i < numclusters;i++)
2717 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2719 if (i == numclusters)
2722 // set up a scissor rectangle for this light
2723 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2726 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2729 if (shadow && (gl_stencil || visiblevolumes))
2731 if (!visiblevolumes)
2733 R_Shadow_Stage_ShadowVolumes();
2736 ent = &cl_entities[0].render;
2737 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2739 memset(&m, 0, sizeof(m));
2740 R_Mesh_Matrix(&ent->matrix);
2741 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2743 m.pointer_vertex = mesh->vertex3f;
2745 GL_LockArrays(0, mesh->numverts);
2746 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2748 // increment stencil if backface is behind depthbuffer
2749 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2750 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2751 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2752 c_rtcached_shadowmeshes++;
2753 c_rtcached_shadowtris += mesh->numtriangles;
2754 // decrement stencil if frontface is behind depthbuffer
2755 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2756 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2758 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2759 c_rtcached_shadowmeshes++;
2760 c_rtcached_shadowtris += mesh->numtriangles;
2761 GL_LockArrays(0, 0);
2764 else if (numsurfaces)
2766 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2767 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2769 if (r_drawentities.integer)
2771 for (i = 0;i < r_refdef.numentities;i++)
2773 ent = r_refdef.entities[i];
2775 if (r_shadow_cull.integer)
2777 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2779 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2782 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2784 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2785 // light emitting entities should not cast their own shadow
2786 if (VectorLength2(relativelightorigin) < 0.1)
2788 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2793 if (!visiblevolumes)
2795 R_Shadow_Stage_Light(usestencil);
2797 ent = &cl_entities[0].render;
2798 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2800 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2801 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2802 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2803 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2804 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2805 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2806 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2807 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2808 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2810 R_Mesh_Matrix(&ent->matrix);
2811 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2812 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);
2815 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2817 if (r_drawentities.integer)
2819 for (i = 0;i < r_refdef.numentities;i++)
2821 ent = r_refdef.entities[i];
2822 // can't draw transparent entity lighting here because
2823 // transparent meshes are deferred for later
2824 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)
2826 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2827 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2828 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2829 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2830 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2831 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2832 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2833 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2834 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);
2841 void R_ShadowVolumeLighting(int visiblevolumes)
2847 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2848 R_Shadow_EditLights_Reload_f();
2852 memset(&m, 0, sizeof(m));
2855 GL_BlendFunc(GL_ONE, GL_ONE);
2856 GL_DepthMask(false);
2857 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2858 qglDisable(GL_CULL_FACE);
2859 GL_Color(0.0, 0.0125, 0.1, 1);
2862 R_Shadow_Stage_Begin();
2863 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2864 if (r_shadow_debuglight.integer >= 0)
2866 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2867 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2868 R_DrawRTLight(&light->rtlight, visiblevolumes);
2871 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2872 if (light->flags & flag)
2873 R_DrawRTLight(&light->rtlight, visiblevolumes);
2875 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2876 R_DrawRTLight(&light->rtlight, visiblevolumes);
2880 qglEnable(GL_CULL_FACE);
2881 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2884 R_Shadow_Stage_End();
2887 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2888 typedef struct suffixinfo_s
2891 qboolean flipx, flipy, flipdiagonal;
2894 static suffixinfo_t suffix[3][6] =
2897 {"px", false, false, false},
2898 {"nx", false, false, false},
2899 {"py", false, false, false},
2900 {"ny", false, false, false},
2901 {"pz", false, false, false},
2902 {"nz", false, false, false}
2905 {"posx", false, false, false},
2906 {"negx", false, false, false},
2907 {"posy", false, false, false},
2908 {"negy", false, false, false},
2909 {"posz", false, false, false},
2910 {"negz", false, false, false}
2913 {"rt", true, false, true},
2914 {"lf", false, true, true},
2915 {"ft", true, true, false},
2916 {"bk", false, false, false},
2917 {"up", true, false, true},
2918 {"dn", true, false, true}
2922 static int componentorder[4] = {0, 1, 2, 3};
2924 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2926 int i, j, cubemapsize;
2927 qbyte *cubemappixels, *image_rgba;
2928 rtexture_t *cubemaptexture;
2930 // must start 0 so the first loadimagepixels has no requested width/height
2932 cubemappixels = NULL;
2933 cubemaptexture = NULL;
2934 // keep trying different suffix groups (posx, px, rt) until one loads
2935 for (j = 0;j < 3 && !cubemappixels;j++)
2937 // load the 6 images in the suffix group
2938 for (i = 0;i < 6;i++)
2940 // generate an image name based on the base and and suffix
2941 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2943 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2945 // an image loaded, make sure width and height are equal
2946 if (image_width == image_height)
2948 // if this is the first image to load successfully, allocate the cubemap memory
2949 if (!cubemappixels && image_width >= 1)
2951 cubemapsize = image_width;
2952 // note this clears to black, so unavailable sides are black
2953 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2955 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2957 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);
2960 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2962 Mem_Free(image_rgba);
2966 // if a cubemap loaded, upload it
2969 if (!r_shadow_filters_texturepool)
2970 r_shadow_filters_texturepool = R_AllocTexturePool();
2971 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2972 Mem_Free(cubemappixels);
2976 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2977 for (j = 0;j < 3;j++)
2978 for (i = 0;i < 6;i++)
2979 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2980 Con_Print(" and was unable to find any of them.\n");
2982 return cubemaptexture;
2985 rtexture_t *R_Shadow_Cubemap(const char *basename)
2988 for (i = 0;i < numcubemaps;i++)
2989 if (!strcasecmp(cubemaps[i].basename, basename))
2990 return cubemaps[i].texture;
2991 if (i >= MAX_CUBEMAPS)
2994 strcpy(cubemaps[i].basename, basename);
2995 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2996 return cubemaps[i].texture;
2999 void R_Shadow_FreeCubemaps(void)
3002 R_FreeTexturePool(&r_shadow_filters_texturepool);
3005 dlight_t *R_Shadow_NewWorldLight(void)
3008 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3009 light->next = r_shadow_worldlightchain;
3010 r_shadow_worldlightchain = light;
3014 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)
3016 VectorCopy(origin, light->origin);
3017 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3018 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3019 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3020 light->color[0] = max(color[0], 0);
3021 light->color[1] = max(color[1], 0);
3022 light->color[2] = max(color[2], 0);
3023 light->radius = max(radius, 0);
3024 light->style = style;
3025 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3027 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3030 light->shadow = shadowenable;
3031 light->corona = corona;
3034 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
3035 light->coronasizescale = coronasizescale;
3036 light->ambientscale = ambientscale;
3037 light->diffusescale = diffusescale;
3038 light->specularscale = specularscale;
3039 light->flags = flags;
3040 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3042 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3045 void R_Shadow_FreeWorldLight(dlight_t *light)
3047 dlight_t **lightpointer;
3048 R_RTLight_Uncompile(&light->rtlight);
3049 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3050 if (*lightpointer != light)
3051 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3052 *lightpointer = light->next;
3056 void R_Shadow_ClearWorldLights(void)
3058 while (r_shadow_worldlightchain)
3059 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3060 r_shadow_selectedlight = NULL;
3061 R_Shadow_FreeCubemaps();
3064 void R_Shadow_SelectLight(dlight_t *light)
3066 if (r_shadow_selectedlight)
3067 r_shadow_selectedlight->selected = false;
3068 r_shadow_selectedlight = light;
3069 if (r_shadow_selectedlight)
3070 r_shadow_selectedlight->selected = true;
3073 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3075 float scale = r_editlights_cursorgrid.value * 0.5f;
3076 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);
3079 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3082 const dlight_t *light;
3085 if (light->selected)
3086 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3089 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);
3092 void R_Shadow_DrawLightSprites(void)
3098 for (i = 0;i < 5;i++)
3100 lighttextures[i] = NULL;
3101 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3102 lighttextures[i] = pic->tex;
3105 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3106 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3107 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3110 void R_Shadow_SelectLightInView(void)
3112 float bestrating, rating, temp[3];
3113 dlight_t *best, *light;
3116 for (light = r_shadow_worldlightchain;light;light = light->next)
3118 VectorSubtract(light->origin, r_vieworigin, temp);
3119 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3122 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3123 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3125 bestrating = rating;
3130 R_Shadow_SelectLight(best);
3133 void R_Shadow_LoadWorldLights(void)
3135 int n, a, style, shadow, flags;
3136 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
3137 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3138 if (r_refdef.worldmodel == NULL)
3140 Con_Print("No map loaded.\n");
3143 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3144 strlcat (name, ".rtlights", sizeof (name));
3145 lightsstring = FS_LoadFile(name, tempmempool, false);
3155 for (;COM_Parse(t, true) && strcmp(
3156 if (COM_Parse(t, true))
3158 if (com_token[0] == '!')
3161 origin[0] = atof(com_token+1);
3164 origin[0] = atof(com_token);
3169 while (*s && *s != '\n')
3175 // check for modifier flags
3181 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);
3183 flags = LIGHTFLAG_REALTIMEMODE;
3191 coronasizescale = 0.25f;
3193 VectorClear(angles);
3196 if (a < 9 || !strcmp(cubemapname, "\"\""))
3198 // remove quotes on cubemapname
3199 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3201 cubemapname[strlen(cubemapname)-1] = 0;
3202 strcpy(cubemapname, cubemapname + 1);
3207 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);
3210 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3211 radius *= r_editlights_rtlightssizescale.value;
3212 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3217 Con_Printf("invalid rtlights file \"%s\"\n", name);
3218 Mem_Free(lightsstring);
3222 void R_Shadow_SaveWorldLights(void)
3225 int bufchars, bufmaxchars;
3227 char name[MAX_QPATH];
3229 if (!r_shadow_worldlightchain)
3231 if (r_refdef.worldmodel == NULL)
3233 Con_Print("No map loaded.\n");
3236 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3237 strlcat (name, ".rtlights", sizeof (name));
3238 bufchars = bufmaxchars = 0;
3240 for (light = r_shadow_worldlightchain;light;light = light->next)
3242 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3243 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);
3244 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3245 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]);
3247 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);
3248 if (bufchars + (int) strlen(line) > bufmaxchars)
3250 bufmaxchars = bufchars + strlen(line) + 2048;
3252 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3256 memcpy(buf, oldbuf, bufchars);
3262 memcpy(buf + bufchars, line, strlen(line));
3263 bufchars += strlen(line);
3267 FS_WriteFile(name, buf, bufchars);
3272 void R_Shadow_LoadLightsFile(void)
3275 char name[MAX_QPATH], *lightsstring, *s, *t;
3276 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3277 if (r_refdef.worldmodel == NULL)
3279 Con_Print("No map loaded.\n");
3282 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3283 strlcat (name, ".lights", sizeof (name));
3284 lightsstring = FS_LoadFile(name, tempmempool, false);
3292 while (*s && *s != '\n')
3297 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);
3301 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);
3304 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3305 radius = bound(15, radius, 4096);
3306 VectorScale(color, (2.0f / (8388608.0f)), color);
3307 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3312 Con_Printf("invalid lights file \"%s\"\n", name);
3313 Mem_Free(lightsstring);
3317 // tyrlite/hmap2 light types in the delay field
3318 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3320 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3322 int entnum, style, islight, skin, pflags, effects, type, n;
3325 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3326 char key[256], value[1024];
3328 if (r_refdef.worldmodel == NULL)
3330 Con_Print("No map loaded.\n");
3333 // try to load a .ent file first
3334 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3335 strlcat (key, ".ent", sizeof (key));
3336 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3337 // and if that is not found, fall back to the bsp file entity string
3339 data = r_refdef.worldmodel->brush.entities;
3342 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3344 type = LIGHTTYPE_MINUSX;
3345 origin[0] = origin[1] = origin[2] = 0;
3346 originhack[0] = originhack[1] = originhack[2] = 0;
3347 angles[0] = angles[1] = angles[2] = 0;
3348 color[0] = color[1] = color[2] = 1;
3349 light[0] = light[1] = light[2] = 1;light[3] = 300;
3350 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3360 if (!COM_ParseToken(&data, false))
3362 if (com_token[0] == '}')
3363 break; // end of entity
3364 if (com_token[0] == '_')
3365 strcpy(key, com_token + 1);
3367 strcpy(key, com_token);
3368 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3369 key[strlen(key)-1] = 0;
3370 if (!COM_ParseToken(&data, false))
3372 strcpy(value, com_token);
3374 // now that we have the key pair worked out...
3375 if (!strcmp("light", key))
3377 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3381 light[0] = vec[0] * (1.0f / 256.0f);
3382 light[1] = vec[0] * (1.0f / 256.0f);
3383 light[2] = vec[0] * (1.0f / 256.0f);
3389 light[0] = vec[0] * (1.0f / 255.0f);
3390 light[1] = vec[1] * (1.0f / 255.0f);
3391 light[2] = vec[2] * (1.0f / 255.0f);
3395 else if (!strcmp("delay", key))
3397 else if (!strcmp("origin", key))
3398 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3399 else if (!strcmp("angle", key))
3400 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3401 else if (!strcmp("angles", key))
3402 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3403 else if (!strcmp("color", key))
3404 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3405 else if (!strcmp("wait", key))
3406 fadescale = atof(value);
3407 else if (!strcmp("classname", key))
3409 if (!strncmp(value, "light", 5))
3412 if (!strcmp(value, "light_fluoro"))
3417 overridecolor[0] = 1;
3418 overridecolor[1] = 1;
3419 overridecolor[2] = 1;
3421 if (!strcmp(value, "light_fluorospark"))
3426 overridecolor[0] = 1;
3427 overridecolor[1] = 1;
3428 overridecolor[2] = 1;
3430 if (!strcmp(value, "light_globe"))
3435 overridecolor[0] = 1;
3436 overridecolor[1] = 0.8;
3437 overridecolor[2] = 0.4;
3439 if (!strcmp(value, "light_flame_large_yellow"))
3444 overridecolor[0] = 1;
3445 overridecolor[1] = 0.5;
3446 overridecolor[2] = 0.1;
3448 if (!strcmp(value, "light_flame_small_yellow"))
3453 overridecolor[0] = 1;
3454 overridecolor[1] = 0.5;
3455 overridecolor[2] = 0.1;
3457 if (!strcmp(value, "light_torch_small_white"))
3462 overridecolor[0] = 1;
3463 overridecolor[1] = 0.5;
3464 overridecolor[2] = 0.1;
3466 if (!strcmp(value, "light_torch_small_walltorch"))
3471 overridecolor[0] = 1;
3472 overridecolor[1] = 0.5;
3473 overridecolor[2] = 0.1;
3477 else if (!strcmp("style", key))
3478 style = atoi(value);
3479 else if (r_refdef.worldmodel->type == mod_brushq3)
3481 if (!strcmp("scale", key))
3482 lightscale = atof(value);
3483 if (!strcmp("fade", key))
3484 fadescale = atof(value);
3486 else if (!strcmp("skin", key))
3487 skin = (int)atof(value);
3488 else if (!strcmp("pflags", key))
3489 pflags = (int)atof(value);
3490 else if (!strcmp("effects", key))
3491 effects = (int)atof(value);
3495 if (lightscale <= 0)
3499 if (color[0] == color[1] && color[0] == color[2])
3501 color[0] *= overridecolor[0];
3502 color[1] *= overridecolor[1];
3503 color[2] *= overridecolor[2];
3505 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3506 color[0] = color[0] * light[0];
3507 color[1] = color[1] * light[1];
3508 color[2] = color[2] * light[2];
3511 case LIGHTTYPE_MINUSX:
3513 case LIGHTTYPE_RECIPX:
3515 VectorScale(color, (1.0f / 16.0f), color);
3517 case LIGHTTYPE_RECIPXX:
3519 VectorScale(color, (1.0f / 16.0f), color);
3522 case LIGHTTYPE_NONE:
3526 case LIGHTTYPE_MINUSXX:
3529 VectorAdd(origin, originhack, origin);
3531 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);
3534 Mem_Free(entfiledata);
3538 void R_Shadow_SetCursorLocationForView(void)
3540 vec_t dist, push, frac;
3541 vec3_t dest, endpos, normal;
3542 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3543 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3546 dist = frac * r_editlights_cursordistance.value;
3547 push = r_editlights_cursorpushback.value;
3551 VectorMA(endpos, push, r_viewforward, endpos);
3552 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3554 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3555 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3556 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3559 void R_Shadow_UpdateWorldLightSelection(void)
3561 if (r_editlights.integer)
3563 R_Shadow_SetCursorLocationForView();
3564 R_Shadow_SelectLightInView();
3565 R_Shadow_DrawLightSprites();
3568 R_Shadow_SelectLight(NULL);
3571 void R_Shadow_EditLights_Clear_f(void)
3573 R_Shadow_ClearWorldLights();
3576 void R_Shadow_EditLights_Reload_f(void)
3578 if (!r_refdef.worldmodel)
3580 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3581 R_Shadow_ClearWorldLights();
3582 R_Shadow_LoadWorldLights();
3583 if (r_shadow_worldlightchain == NULL)
3585 R_Shadow_LoadLightsFile();
3586 if (r_shadow_worldlightchain == NULL)
3587 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3591 void R_Shadow_EditLights_Save_f(void)
3593 if (!r_refdef.worldmodel)
3595 R_Shadow_SaveWorldLights();
3598 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3600 R_Shadow_ClearWorldLights();
3601 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3604 void R_Shadow_EditLights_ImportLightsFile_f(void)
3606 R_Shadow_ClearWorldLights();
3607 R_Shadow_LoadLightsFile();
3610 void R_Shadow_EditLights_Spawn_f(void)
3613 if (!r_editlights.integer)
3615 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3618 if (Cmd_Argc() != 1)
3620 Con_Print("r_editlights_spawn does not take parameters\n");
3623 color[0] = color[1] = color[2] = 1;
3624 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3627 void R_Shadow_EditLights_Edit_f(void)
3629 vec3_t origin, angles, color;
3630 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3631 int style, shadows, flags, normalmode, realtimemode;
3632 char cubemapname[1024];
3633 if (!r_editlights.integer)
3635 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3638 if (!r_shadow_selectedlight)
3640 Con_Print("No selected light.\n");
3643 VectorCopy(r_shadow_selectedlight->origin, origin);
3644 VectorCopy(r_shadow_selectedlight->angles, angles);
3645 VectorCopy(r_shadow_selectedlight->color, color);
3646 radius = r_shadow_selectedlight->radius;
3647 style = r_shadow_selectedlight->style;
3648 if (r_shadow_selectedlight->cubemapname)
3649 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3652 shadows = r_shadow_selectedlight->shadow;
3653 corona = r_shadow_selectedlight->corona;
3654 coronasizescale = r_shadow_selectedlight->coronasizescale;
3655 ambientscale = r_shadow_selectedlight->ambientscale;
3656 diffusescale = r_shadow_selectedlight->diffusescale;
3657 specularscale = r_shadow_selectedlight->specularscale;
3658 flags = r_shadow_selectedlight->flags;
3659 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3660 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3661 if (!strcmp(Cmd_Argv(1), "origin"))
3663 if (Cmd_Argc() != 5)
3665 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3668 origin[0] = atof(Cmd_Argv(2));
3669 origin[1] = atof(Cmd_Argv(3));
3670 origin[2] = atof(Cmd_Argv(4));
3672 else if (!strcmp(Cmd_Argv(1), "originx"))
3674 if (Cmd_Argc() != 3)
3676 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3679 origin[0] = atof(Cmd_Argv(2));
3681 else if (!strcmp(Cmd_Argv(1), "originy"))
3683 if (Cmd_Argc() != 3)
3685 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3688 origin[1] = atof(Cmd_Argv(2));
3690 else if (!strcmp(Cmd_Argv(1), "originz"))
3692 if (Cmd_Argc() != 3)
3694 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3697 origin[2] = atof(Cmd_Argv(2));
3699 else if (!strcmp(Cmd_Argv(1), "move"))
3701 if (Cmd_Argc() != 5)
3703 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3706 origin[0] += atof(Cmd_Argv(2));
3707 origin[1] += atof(Cmd_Argv(3));
3708 origin[2] += atof(Cmd_Argv(4));
3710 else if (!strcmp(Cmd_Argv(1), "movex"))
3712 if (Cmd_Argc() != 3)
3714 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3717 origin[0] += atof(Cmd_Argv(2));
3719 else if (!strcmp(Cmd_Argv(1), "movey"))
3721 if (Cmd_Argc() != 3)
3723 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3726 origin[1] += atof(Cmd_Argv(2));
3728 else if (!strcmp(Cmd_Argv(1), "movez"))
3730 if (Cmd_Argc() != 3)
3732 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3735 origin[2] += atof(Cmd_Argv(2));
3737 else if (!strcmp(Cmd_Argv(1), "angles"))
3739 if (Cmd_Argc() != 5)
3741 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3744 angles[0] = atof(Cmd_Argv(2));
3745 angles[1] = atof(Cmd_Argv(3));
3746 angles[2] = atof(Cmd_Argv(4));
3748 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3750 if (Cmd_Argc() != 3)
3752 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3755 angles[0] = atof(Cmd_Argv(2));
3757 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3759 if (Cmd_Argc() != 3)
3761 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3764 angles[1] = atof(Cmd_Argv(2));
3766 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3768 if (Cmd_Argc() != 3)
3770 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3773 angles[2] = atof(Cmd_Argv(2));
3775 else if (!strcmp(Cmd_Argv(1), "color"))
3777 if (Cmd_Argc() != 5)
3779 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3782 color[0] = atof(Cmd_Argv(2));
3783 color[1] = atof(Cmd_Argv(3));
3784 color[2] = atof(Cmd_Argv(4));
3786 else if (!strcmp(Cmd_Argv(1), "radius"))
3788 if (Cmd_Argc() != 3)
3790 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3793 radius = atof(Cmd_Argv(2));
3795 else if (!strcmp(Cmd_Argv(1), "style"))
3797 if (Cmd_Argc() != 3)
3799 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3802 style = atoi(Cmd_Argv(2));
3804 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3808 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3811 if (Cmd_Argc() == 3)
3812 strcpy(cubemapname, Cmd_Argv(2));
3816 else if (!strcmp(Cmd_Argv(1), "shadows"))
3818 if (Cmd_Argc() != 3)
3820 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3823 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3825 else if (!strcmp(Cmd_Argv(1), "corona"))
3827 if (Cmd_Argc() != 3)
3829 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3832 corona = atof(Cmd_Argv(2));
3834 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3836 if (Cmd_Argc() != 3)
3838 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3841 coronasizescale = atof(Cmd_Argv(2));
3843 else if (!strcmp(Cmd_Argv(1), "ambient"))
3845 if (Cmd_Argc() != 3)
3847 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3850 ambientscale = atof(Cmd_Argv(2));
3852 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3854 if (Cmd_Argc() != 3)
3856 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3859 diffusescale = atof(Cmd_Argv(2));
3861 else if (!strcmp(Cmd_Argv(1), "specular"))
3863 if (Cmd_Argc() != 3)
3865 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3868 specularscale = atof(Cmd_Argv(2));
3870 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3872 if (Cmd_Argc() != 3)
3874 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3877 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3879 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3881 if (Cmd_Argc() != 3)
3883 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3886 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3890 Con_Print("usage: r_editlights_edit [property] [value]\n");
3891 Con_Print("Selected light's properties:\n");
3892 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3893 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3894 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3895 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3896 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3897 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3898 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3899 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3900 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3901 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3902 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3903 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3904 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3905 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3908 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3909 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3912 void R_Shadow_EditLights_EditAll_f(void)
3916 if (!r_editlights.integer)
3918 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3922 for (light = r_shadow_worldlightchain;light;light = light->next)
3924 R_Shadow_SelectLight(light);
3925 R_Shadow_EditLights_Edit_f();
3929 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3931 int lightnumber, lightcount;
3935 if (!r_editlights.integer)
3941 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3942 if (light == r_shadow_selectedlight)
3943 lightnumber = lightcount;
3944 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;
3945 if (r_shadow_selectedlight == NULL)
3947 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3948 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;
3949 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;
3950 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;
3951 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3952 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3953 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3954 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;
3955 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3956 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3957 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3958 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3959 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3960 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;
3961 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;
3964 void R_Shadow_EditLights_ToggleShadow_f(void)
3966 if (!r_editlights.integer)
3968 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3971 if (!r_shadow_selectedlight)
3973 Con_Print("No selected light.\n");
3976 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);
3979 void R_Shadow_EditLights_ToggleCorona_f(void)
3981 if (!r_editlights.integer)
3983 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3986 if (!r_shadow_selectedlight)
3988 Con_Print("No selected light.\n");
3991 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);
3994 void R_Shadow_EditLights_Remove_f(void)
3996 if (!r_editlights.integer)
3998 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4001 if (!r_shadow_selectedlight)
4003 Con_Print("No selected light.\n");
4006 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4007 r_shadow_selectedlight = NULL;
4010 void R_Shadow_EditLights_Help_f(void)
4013 "Documentation on r_editlights system:\n"
4015 "r_editlights : enable/disable editing mode\n"
4016 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4017 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4018 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4019 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4020 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4021 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4022 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4024 "r_editlights_help : this help\n"
4025 "r_editlights_clear : remove all lights\n"
4026 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4027 "r_editlights_save : save to .rtlights file\n"
4028 "r_editlights_spawn : create a light with default settings\n"
4029 "r_editlights_edit command : edit selected light - more documentation below\n"
4030 "r_editlights_remove : remove selected light\n"
4031 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4032 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4033 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4035 "origin x y z : set light location\n"
4036 "originx x: set x component of light location\n"
4037 "originy y: set y component of light location\n"
4038 "originz z: set z component of light location\n"
4039 "move x y z : adjust light location\n"
4040 "movex x: adjust x component of light location\n"
4041 "movey y: adjust y component of light location\n"
4042 "movez z: adjust z component of light location\n"
4043 "angles x y z : set light angles\n"
4044 "anglesx x: set x component of light angles\n"
4045 "anglesy y: set y component of light angles\n"
4046 "anglesz z: set z component of light angles\n"
4047 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4048 "radius radius : set radius (size) of light\n"
4049 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4050 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4051 "shadows 1/0 : turn on/off shadows\n"
4052 "corona n : set corona intensity\n"
4053 "coronasize n : set corona size (0-1)\n"
4054 "ambient n : set ambient intensity (0-1)\n"
4055 "diffuse n : set diffuse intensity (0-1)\n"
4056 "specular n : set specular intensity (0-1)\n"
4057 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4058 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4059 "<nothing> : print light properties to console\n"
4063 void R_Shadow_EditLights_CopyInfo_f(void)
4065 if (!r_editlights.integer)
4067 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4070 if (!r_shadow_selectedlight)
4072 Con_Print("No selected light.\n");
4075 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4076 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4077 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4078 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4079 if (r_shadow_selectedlight->cubemapname)
4080 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4082 r_shadow_bufferlight.cubemapname[0] = 0;
4083 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4084 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4085 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4086 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4087 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4088 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4089 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4092 void R_Shadow_EditLights_PasteInfo_f(void)
4094 if (!r_editlights.integer)
4096 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4099 if (!r_shadow_selectedlight)
4101 Con_Print("No selected light.\n");
4104 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);
4107 void R_Shadow_EditLights_Init(void)
4109 Cvar_RegisterVariable(&r_editlights);
4110 Cvar_RegisterVariable(&r_editlights_cursordistance);
4111 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4112 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4113 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4114 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4115 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4116 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4117 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4118 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4119 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4120 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4121 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4122 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4123 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4124 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4125 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4126 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4127 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4128 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4129 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4130 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);