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
477 Mem_Free(fragstring);
479 Mem_Free(vertstring);
483 void r_shadow_shutdown(void)
486 R_Shadow_UncompileWorldLights();
487 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
489 if (r_shadow_program_light[i])
491 GL_Backend_FreeProgram(r_shadow_program_light[i]);
492 r_shadow_program_light[i] = 0;
496 r_shadow_normalcubetexture = NULL;
497 r_shadow_attenuation2dtexture = NULL;
498 r_shadow_attenuation3dtexture = NULL;
499 r_shadow_blankbumptexture = NULL;
500 r_shadow_blankglosstexture = NULL;
501 r_shadow_blankwhitetexture = NULL;
502 r_shadow_blankwhitecubetexture = NULL;
503 r_shadow_blankblacktexture = NULL;
504 R_FreeTexturePool(&r_shadow_texturepool);
505 R_FreeTexturePool(&r_shadow_filters_texturepool);
506 maxshadowelements = 0;
508 Mem_Free(shadowelements);
509 shadowelements = NULL;
512 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
521 Mem_Free(shadowmark);
524 Mem_Free(shadowmarklist);
525 shadowmarklist = NULL;
527 r_shadow_buffer_numclusterpvsbytes = 0;
528 if (r_shadow_buffer_clusterpvs)
529 Mem_Free(r_shadow_buffer_clusterpvs);
530 r_shadow_buffer_clusterpvs = NULL;
531 if (r_shadow_buffer_clusterlist)
532 Mem_Free(r_shadow_buffer_clusterlist);
533 r_shadow_buffer_clusterlist = NULL;
534 r_shadow_buffer_numsurfacepvsbytes = 0;
535 if (r_shadow_buffer_surfacepvs)
536 Mem_Free(r_shadow_buffer_surfacepvs);
537 r_shadow_buffer_surfacepvs = NULL;
538 if (r_shadow_buffer_surfacelist)
539 Mem_Free(r_shadow_buffer_surfacelist);
540 r_shadow_buffer_surfacelist = NULL;
543 void r_shadow_newmap(void)
547 void R_Shadow_Help_f(void)
550 "Documentation on r_shadow system:\n"
552 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
553 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
554 "r_shadow_debuglight : render only this light number (-1 = all)\n"
555 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
556 "r_shadow_gloss2intensity : brightness of forced gloss\n"
557 "r_shadow_glossintensity : brightness of textured gloss\n"
558 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
559 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
560 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
561 "r_shadow_portallight : use portal visibility for static light precomputation\n"
562 "r_shadow_projectdistance : shadow volume projection distance\n"
563 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
564 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
565 "r_shadow_realtime_world : use high quality world lighting mode\n"
566 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
567 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
568 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
569 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
570 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
571 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
572 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
573 "r_shadow_scissor : use scissor optimization\n"
574 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
575 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
576 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
577 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
578 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
580 "r_shadow_help : this help\n"
584 void R_Shadow_Init(void)
586 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
587 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
588 Cvar_RegisterVariable(&r_shadow_cull);
589 Cvar_RegisterVariable(&r_shadow_debuglight);
590 Cvar_RegisterVariable(&r_shadow_gloss);
591 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
592 Cvar_RegisterVariable(&r_shadow_glossintensity);
593 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
594 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
595 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
596 Cvar_RegisterVariable(&r_shadow_portallight);
597 Cvar_RegisterVariable(&r_shadow_projectdistance);
598 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
599 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
600 Cvar_RegisterVariable(&r_shadow_realtime_world);
601 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
602 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
603 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
604 Cvar_RegisterVariable(&r_shadow_scissor);
605 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
606 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
607 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
608 Cvar_RegisterVariable(&r_shadow_staticworldlights);
609 Cvar_RegisterVariable(&r_shadow_texture3d);
610 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
611 Cvar_RegisterVariable(&r_shadow_glsl);
612 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
613 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
614 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
615 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
616 if (gamemode == GAME_TENEBRAE)
618 Cvar_SetValue("r_shadow_gloss", 2);
619 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
621 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
622 R_Shadow_EditLights_Init();
623 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
624 r_shadow_worldlightchain = NULL;
625 maxshadowelements = 0;
626 shadowelements = NULL;
634 shadowmarklist = NULL;
636 r_shadow_buffer_numclusterpvsbytes = 0;
637 r_shadow_buffer_clusterpvs = NULL;
638 r_shadow_buffer_clusterlist = NULL;
639 r_shadow_buffer_numsurfacepvsbytes = 0;
640 r_shadow_buffer_surfacepvs = NULL;
641 r_shadow_buffer_surfacelist = NULL;
642 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
645 matrix4x4_t matrix_attenuationxyz =
648 {0.5, 0.0, 0.0, 0.5},
649 {0.0, 0.5, 0.0, 0.5},
650 {0.0, 0.0, 0.5, 0.5},
655 matrix4x4_t matrix_attenuationz =
658 {0.0, 0.0, 0.5, 0.5},
659 {0.0, 0.0, 0.0, 0.5},
660 {0.0, 0.0, 0.0, 0.5},
665 int *R_Shadow_ResizeShadowElements(int numtris)
667 // make sure shadowelements is big enough for this volume
668 if (maxshadowelements < numtris * 24)
670 maxshadowelements = numtris * 24;
672 Mem_Free(shadowelements);
673 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
675 return shadowelements;
678 void R_Shadow_EnlargeClusterBuffer(int numclusters)
680 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
681 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
683 if (r_shadow_buffer_clusterpvs)
684 Mem_Free(r_shadow_buffer_clusterpvs);
685 if (r_shadow_buffer_clusterlist)
686 Mem_Free(r_shadow_buffer_clusterlist);
687 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
688 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
689 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
693 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
695 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
696 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
698 if (r_shadow_buffer_surfacepvs)
699 Mem_Free(r_shadow_buffer_surfacepvs);
700 if (r_shadow_buffer_surfacelist)
701 Mem_Free(r_shadow_buffer_surfacelist);
702 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
703 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
704 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
708 void R_Shadow_PrepareShadowMark(int numtris)
710 // make sure shadowmark is big enough for this volume
711 if (maxshadowmark < numtris)
713 maxshadowmark = numtris;
715 Mem_Free(shadowmark);
717 Mem_Free(shadowmarklist);
718 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
719 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
723 // if shadowmarkcount wrapped we clear the array and adjust accordingly
724 if (shadowmarkcount == 0)
727 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
732 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)
734 int i, j, tris = 0, vr[3], t, outvertices = 0;
739 if (maxvertexupdate < innumvertices)
741 maxvertexupdate = innumvertices;
743 Mem_Free(vertexupdate);
745 Mem_Free(vertexremap);
746 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
747 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
751 if (vertexupdatenum == 0)
754 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
755 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
758 for (i = 0;i < numshadowmarktris;i++)
759 shadowmark[shadowmarktris[i]] = shadowmarkcount;
761 for (i = 0;i < numshadowmarktris;i++)
763 t = shadowmarktris[i];
764 e = inelement3i + t * 3;
765 // make sure the vertices are created
766 for (j = 0;j < 3;j++)
768 if (vertexupdate[e[j]] != vertexupdatenum)
770 vertexupdate[e[j]] = vertexupdatenum;
771 vertexremap[e[j]] = outvertices;
772 v = invertex3f + e[j] * 3;
773 // project one copy of the vertex to the sphere radius of the light
774 // (FIXME: would projecting it to the light box be better?)
775 VectorSubtract(v, projectorigin, temp);
776 f = projectdistance / VectorLength(temp);
777 VectorCopy(v, outvertex3f);
778 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
785 for (i = 0;i < numshadowmarktris;i++)
787 t = shadowmarktris[i];
788 e = inelement3i + t * 3;
789 n = inneighbor3i + t * 3;
790 // output the front and back triangles
791 outelement3i[0] = vertexremap[e[0]];
792 outelement3i[1] = vertexremap[e[1]];
793 outelement3i[2] = vertexremap[e[2]];
794 outelement3i[3] = vertexremap[e[2]] + 1;
795 outelement3i[4] = vertexremap[e[1]] + 1;
796 outelement3i[5] = vertexremap[e[0]] + 1;
799 // output the sides (facing outward from this triangle)
800 if (shadowmark[n[0]] != shadowmarkcount)
802 vr[0] = vertexremap[e[0]];
803 vr[1] = vertexremap[e[1]];
804 outelement3i[0] = vr[1];
805 outelement3i[1] = vr[0];
806 outelement3i[2] = vr[0] + 1;
807 outelement3i[3] = vr[1];
808 outelement3i[4] = vr[0] + 1;
809 outelement3i[5] = vr[1] + 1;
813 if (shadowmark[n[1]] != shadowmarkcount)
815 vr[1] = vertexremap[e[1]];
816 vr[2] = vertexremap[e[2]];
817 outelement3i[0] = vr[2];
818 outelement3i[1] = vr[1];
819 outelement3i[2] = vr[1] + 1;
820 outelement3i[3] = vr[2];
821 outelement3i[4] = vr[1] + 1;
822 outelement3i[5] = vr[2] + 1;
826 if (shadowmark[n[2]] != shadowmarkcount)
828 vr[0] = vertexremap[e[0]];
829 vr[2] = vertexremap[e[2]];
830 outelement3i[0] = vr[0];
831 outelement3i[1] = vr[2];
832 outelement3i[2] = vr[2] + 1;
833 outelement3i[3] = vr[0];
834 outelement3i[4] = vr[2] + 1;
835 outelement3i[5] = vr[0] + 1;
841 *outnumvertices = outvertices;
845 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)
848 if (projectdistance < 0.1)
850 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
853 if (!numverts || !nummarktris)
855 // make sure shadowelements is big enough for this volume
856 if (maxshadowelements < nummarktris * 24)
857 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
858 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
859 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
862 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)
867 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
869 tend = firsttriangle + numtris;
870 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
871 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
872 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
874 // surface box entirely inside light box, no box cull
875 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
876 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
877 shadowmarklist[numshadowmark++] = t;
881 // surface box not entirely inside light box, cull each triangle
882 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
884 v[0] = invertex3f + e[0] * 3;
885 v[1] = invertex3f + e[1] * 3;
886 v[2] = invertex3f + e[2] * 3;
887 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
888 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
889 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
890 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
891 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
892 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
893 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
894 shadowmarklist[numshadowmark++] = t;
899 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
902 if (r_shadow_compilingrtlight)
904 // if we're compiling an rtlight, capture the mesh
905 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
908 memset(&m, 0, sizeof(m));
909 m.pointer_vertex = vertex3f;
911 GL_LockArrays(0, numvertices);
912 if (r_shadowstage == SHADOWSTAGE_STENCIL)
914 // increment stencil if backface is behind depthbuffer
915 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
916 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
917 R_Mesh_Draw(numvertices, numtriangles, element3i);
919 c_rt_shadowtris += numtriangles;
920 // decrement stencil if frontface is behind depthbuffer
921 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
922 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
924 R_Mesh_Draw(numvertices, numtriangles, element3i);
926 c_rt_shadowtris += numtriangles;
930 static void R_Shadow_MakeTextures(void)
932 int x, y, z, d, side;
933 float v[3], s, t, intensity;
935 R_FreeTexturePool(&r_shadow_texturepool);
936 r_shadow_texturepool = R_AllocTexturePool();
937 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
938 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
940 #define ATTEN2DSIZE 64
941 #define ATTEN3DSIZE 32
942 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
947 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
952 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
957 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
962 r_shadow_blankblacktexture = R_LoadTexture2D(r_shadow_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
963 r_shadow_blankwhitecubetexture = NULL;
964 r_shadow_normalcubetexture = NULL;
965 if (gl_texturecubemap)
967 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
968 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
969 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
970 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
971 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
972 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
973 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
974 for (side = 0;side < 6;side++)
976 for (y = 0;y < NORMSIZE;y++)
978 for (x = 0;x < NORMSIZE;x++)
980 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
981 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1015 intensity = 127.0f / sqrt(DotProduct(v, v));
1016 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1017 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1018 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1019 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1023 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1025 for (y = 0;y < ATTEN2DSIZE;y++)
1027 for (x = 0;x < ATTEN2DSIZE;x++)
1029 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1030 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1032 intensity = 1.0f - sqrt(DotProduct(v, v));
1034 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1035 d = bound(0, intensity, 255);
1036 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1037 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1038 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1039 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1042 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1043 if (r_shadow_texture3d.integer)
1045 for (z = 0;z < ATTEN3DSIZE;z++)
1047 for (y = 0;y < ATTEN3DSIZE;y++)
1049 for (x = 0;x < ATTEN3DSIZE;x++)
1051 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1052 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1053 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1054 intensity = 1.0f - sqrt(DotProduct(v, v));
1056 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1057 d = bound(0, intensity, 255);
1058 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1059 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1060 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1061 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1065 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1070 void R_Shadow_ValidateCvars(void)
1072 if (r_shadow_texture3d.integer && !gl_texture3d)
1073 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1074 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1075 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1078 void R_Shadow_Stage_Begin(void)
1082 R_Shadow_ValidateCvars();
1084 if (!r_shadow_attenuation2dtexture
1085 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1086 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1087 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1088 R_Shadow_MakeTextures();
1090 memset(&m, 0, sizeof(m));
1091 GL_BlendFunc(GL_ONE, GL_ZERO);
1092 GL_DepthMask(false);
1095 GL_Color(0, 0, 0, 1);
1096 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1097 qglEnable(GL_CULL_FACE);
1098 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1099 r_shadowstage = SHADOWSTAGE_NONE;
1102 void R_Shadow_Stage_ShadowVolumes(void)
1105 memset(&m, 0, sizeof(m));
1107 GL_Color(1, 1, 1, 1);
1108 GL_ColorMask(0, 0, 0, 0);
1109 GL_BlendFunc(GL_ONE, GL_ZERO);
1110 GL_DepthMask(false);
1112 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1113 //if (r_shadow_shadow_polygonoffset.value != 0)
1115 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1116 // qglEnable(GL_POLYGON_OFFSET_FILL);
1119 // qglDisable(GL_POLYGON_OFFSET_FILL);
1120 qglDepthFunc(GL_LESS);
1121 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1122 qglEnable(GL_STENCIL_TEST);
1123 qglStencilFunc(GL_ALWAYS, 128, ~0);
1124 if (gl_ext_stenciltwoside.integer)
1126 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1127 qglDisable(GL_CULL_FACE);
1128 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1129 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1131 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1132 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1134 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1138 r_shadowstage = SHADOWSTAGE_STENCIL;
1139 qglEnable(GL_CULL_FACE);
1141 // this is changed by every shadow render so its value here is unimportant
1142 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1144 GL_Clear(GL_STENCIL_BUFFER_BIT);
1146 // LordHavoc note: many shadow volumes reside entirely inside the world
1147 // (that is to say they are entirely bounded by their lit surfaces),
1148 // which can be optimized by handling things as an inverted light volume,
1149 // with the shadow boundaries of the world being simulated by an altered
1150 // (129) bias to stencil clearing on such lights
1151 // FIXME: generate inverted light volumes for use as shadow volumes and
1152 // optimize for them as noted above
1155 void R_Shadow_Stage_Light(int shadowtest)
1158 memset(&m, 0, sizeof(m));
1160 GL_BlendFunc(GL_ONE, GL_ONE);
1161 GL_DepthMask(false);
1163 qglPolygonOffset(0, 0);
1164 //qglDisable(GL_POLYGON_OFFSET_FILL);
1165 GL_Color(1, 1, 1, 1);
1166 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1167 qglDepthFunc(GL_EQUAL);
1168 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1169 qglEnable(GL_CULL_FACE);
1171 qglEnable(GL_STENCIL_TEST);
1173 qglDisable(GL_STENCIL_TEST);
1174 if (gl_support_stenciltwoside)
1175 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1177 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1178 // only draw light where this geometry was already rendered AND the
1179 // stencil is 128 (values other than this mean shadow)
1180 qglStencilFunc(GL_EQUAL, 128, ~0);
1181 r_shadowstage = SHADOWSTAGE_LIGHT;
1185 void R_Shadow_Stage_End(void)
1188 memset(&m, 0, sizeof(m));
1190 GL_BlendFunc(GL_ONE, GL_ZERO);
1193 qglPolygonOffset(0, 0);
1194 //qglDisable(GL_POLYGON_OFFSET_FILL);
1195 GL_Color(1, 1, 1, 1);
1196 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1197 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1198 qglDepthFunc(GL_LEQUAL);
1199 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1200 qglDisable(GL_STENCIL_TEST);
1201 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1202 if (gl_support_stenciltwoside)
1203 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1205 qglStencilFunc(GL_ALWAYS, 128, ~0);
1206 r_shadowstage = SHADOWSTAGE_NONE;
1209 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1211 int i, ix1, iy1, ix2, iy2;
1212 float x1, y1, x2, y2, x, y, f;
1213 vec3_t smins, smaxs;
1215 if (!r_shadow_scissor.integer)
1217 // if view is inside the box, just say yes it's visible
1218 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1220 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1223 for (i = 0;i < 3;i++)
1225 if (r_viewforward[i] >= 0)
1236 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1237 if (DotProduct(r_viewforward, v2) <= f)
1239 // entirely behind nearclip plane
1242 if (DotProduct(r_viewforward, v) >= f)
1244 // entirely infront of nearclip plane
1245 x1 = y1 = x2 = y2 = 0;
1246 for (i = 0;i < 8;i++)
1248 v[0] = (i & 1) ? mins[0] : maxs[0];
1249 v[1] = (i & 2) ? mins[1] : maxs[1];
1250 v[2] = (i & 4) ? mins[2] : maxs[2];
1252 GL_TransformToScreen(v, v2);
1253 //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]);
1272 // clipped by nearclip plane
1273 // this is nasty and crude...
1274 // create viewspace bbox
1275 for (i = 0;i < 8;i++)
1277 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1278 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1279 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1280 v2[0] = -DotProduct(v, r_viewleft);
1281 v2[1] = DotProduct(v, r_viewup);
1282 v2[2] = DotProduct(v, r_viewforward);
1285 if (smins[0] > v2[0]) smins[0] = v2[0];
1286 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1287 if (smins[1] > v2[1]) smins[1] = v2[1];
1288 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1289 if (smins[2] > v2[2]) smins[2] = v2[2];
1290 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1294 smins[0] = smaxs[0] = v2[0];
1295 smins[1] = smaxs[1] = v2[1];
1296 smins[2] = smaxs[2] = v2[2];
1299 // now we have a bbox in viewspace
1300 // clip it to the view plane
1303 // return true if that culled the box
1304 if (smins[2] >= smaxs[2])
1306 // ok some of it is infront of the view, transform each corner back to
1307 // worldspace and then to screenspace and make screen rect
1308 // initialize these variables just to avoid compiler warnings
1309 x1 = y1 = x2 = y2 = 0;
1310 for (i = 0;i < 8;i++)
1312 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1313 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1314 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1315 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1316 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1317 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1319 GL_TransformToScreen(v, v2);
1320 //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]);
1337 // this code doesn't handle boxes with any points behind view properly
1338 x1 = 1000;x2 = -1000;
1339 y1 = 1000;y2 = -1000;
1340 for (i = 0;i < 8;i++)
1342 v[0] = (i & 1) ? mins[0] : maxs[0];
1343 v[1] = (i & 2) ? mins[1] : maxs[1];
1344 v[2] = (i & 4) ? mins[2] : maxs[2];
1346 GL_TransformToScreen(v, v2);
1347 //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]);
1365 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1366 if (ix1 < r_view_x) ix1 = r_view_x;
1367 if (iy1 < r_view_y) iy1 = r_view_y;
1368 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1369 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1370 if (ix2 <= ix1 || iy2 <= iy1)
1372 // set up the scissor rectangle
1373 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1374 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1375 //qglEnable(GL_SCISSOR_TEST);
1380 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1382 float *color4f = varray_color4f;
1383 float dist, dot, intensity, v[3], n[3];
1384 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1386 Matrix4x4_Transform(m, vertex3f, v);
1387 if ((dist = DotProduct(v, v)) < 1)
1389 Matrix4x4_Transform3x3(m, normal3f, n);
1390 if ((dot = DotProduct(n, v)) > 0)
1393 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1394 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1395 VectorScale(lightcolor, intensity, color4f);
1400 VectorClear(color4f);
1406 VectorClear(color4f);
1412 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1414 float *color4f = varray_color4f;
1415 float dist, dot, intensity, v[3], n[3];
1416 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1418 Matrix4x4_Transform(m, vertex3f, v);
1419 if ((dist = fabs(v[2])) < 1)
1421 Matrix4x4_Transform3x3(m, normal3f, n);
1422 if ((dot = DotProduct(n, v)) > 0)
1424 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1425 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1426 VectorScale(lightcolor, intensity, color4f);
1431 VectorClear(color4f);
1437 VectorClear(color4f);
1443 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1445 float *color4f = varray_color4f;
1446 float dot, intensity, v[3], n[3];
1447 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1449 Matrix4x4_Transform(m, vertex3f, v);
1450 Matrix4x4_Transform3x3(m, normal3f, n);
1451 if ((dot = DotProduct(n, v)) > 0)
1453 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1454 VectorScale(lightcolor, intensity, color4f);
1459 VectorClear(color4f);
1465 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1467 float *color4f = varray_color4f;
1468 float dist, intensity, v[3];
1469 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1471 Matrix4x4_Transform(m, vertex3f, v);
1472 if ((dist = DotProduct(v, v)) < 1)
1475 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1476 VectorScale(lightcolor, intensity, color4f);
1481 VectorClear(color4f);
1487 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1489 float *color4f = varray_color4f;
1490 float dist, intensity, v[3];
1491 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1493 Matrix4x4_Transform(m, vertex3f, v);
1494 if ((dist = fabs(v[2])) < 1)
1496 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1497 VectorScale(lightcolor, intensity, color4f);
1502 VectorClear(color4f);
1508 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1509 #define USETEXMATRIX
1511 #ifndef USETEXMATRIX
1512 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1513 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1514 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1518 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1519 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1520 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1527 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1531 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1532 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1540 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)
1544 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1546 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1547 // the cubemap normalizes this for us
1548 out3f[0] = DotProduct(svector3f, lightdir);
1549 out3f[1] = DotProduct(tvector3f, lightdir);
1550 out3f[2] = DotProduct(normal3f, lightdir);
1554 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)
1557 float lightdir[3], eyedir[3], halfdir[3];
1558 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1560 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1561 VectorNormalizeFast(lightdir);
1562 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1563 VectorNormalizeFast(eyedir);
1564 VectorAdd(lightdir, eyedir, halfdir);
1565 // the cubemap normalizes this for us
1566 out3f[0] = DotProduct(svector3f, halfdir);
1567 out3f[1] = DotProduct(tvector3f, halfdir);
1568 out3f[2] = DotProduct(normal3f, halfdir);
1572 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)
1575 float color[3], color2[3], colorscale;
1577 // FIXME: support EF_NODEPTHTEST
1578 GL_DepthMask(false);
1581 bumptexture = r_shadow_blankbumptexture;
1582 specularscale *= r_shadow_glossintensity.value;
1585 if (r_shadow_gloss.integer >= 2)
1587 glosstexture = r_shadow_blankglosstexture;
1588 specularscale *= r_shadow_gloss2intensity.value;
1592 glosstexture = r_shadow_blankblacktexture;
1596 if (r_shadow_gloss.integer < 1)
1599 lightcubemap = r_shadow_blankwhitecubetexture;
1600 if (ambientscale + diffusescale + specularscale < 0.01)
1602 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1604 unsigned int perm, prog;
1605 // GLSL shader path (GFFX5200, Radeon 9500)
1606 memset(&m, 0, sizeof(m));
1607 m.pointer_vertex = vertex3f;
1608 m.pointer_texcoord[0] = texcoord2f;
1609 m.pointer_texcoord3f[1] = svector3f;
1610 m.pointer_texcoord3f[2] = tvector3f;
1611 m.pointer_texcoord3f[3] = normal3f;
1612 m.tex[0] = R_GetTexture(bumptexture);
1613 m.tex[1] = R_GetTexture(basetexture);
1614 m.tex[2] = R_GetTexture(glosstexture);
1615 m.texcubemap[3] = R_GetTexture(lightcubemap);
1616 // TODO: support fog (after renderer is converted to texture fog)
1617 m.tex[4] = R_GetTexture(r_shadow_blankwhitetexture);
1618 m.texmatrix[3] = *matrix_modeltolight;
1620 GL_BlendFunc(GL_ONE, GL_ONE);
1621 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1625 perm |= SHADERPERMUTATION_SPECULAR;
1627 // perm |= SHADERPERMUTATION_FOG;
1629 perm |= SHADERPERMUTATION_CUBEFILTER;
1630 if (r_shadow_glsl_offsetmapping.integer)
1631 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1632 prog = r_shadow_program_light[perm];
1633 qglUseProgramObjectARB(r_shadow_program_light[perm]);
1634 // TODO: support fog (after renderer is converted to texture fog)
1635 if (perm & SHADERPERMUTATION_FOG)
1636 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);
1637 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);
1638 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);
1639 if (perm & SHADERPERMUTATION_SPECULAR)
1641 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);
1642 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);
1644 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);
1645 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);
1646 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1647 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);
1648 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1650 // these are * 0.25 because the offsetmapping shader does the process 4 times
1651 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value * 0.25);
1652 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value * 0.25);
1655 GL_LockArrays(0, numverts);
1656 R_Mesh_Draw(numverts, numtriangles, elements);
1658 c_rt_lighttris += numtriangles;
1659 GL_LockArrays(0, 0);
1660 qglUseProgramObjectARB(0);
1662 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1665 bumptexture = r_shadow_blankbumptexture;
1667 glosstexture = r_shadow_blankglosstexture;
1671 colorscale = ambientscale;
1672 // colorscale accounts for how much we multiply the brightness
1675 // mult is how many times the final pass of the lighting will be
1676 // performed to get more brightness than otherwise possible.
1678 // Limit mult to 64 for sanity sake.
1679 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1681 // 3 3D combine path (Geforce3, Radeon 8500)
1682 memset(&m, 0, sizeof(m));
1683 m.pointer_vertex = vertex3f;
1684 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1686 m.pointer_texcoord3f[0] = vertex3f;
1687 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1689 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1690 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1692 m.tex[1] = R_GetTexture(basetexture);
1693 m.pointer_texcoord[1] = texcoord2f;
1694 m.texcubemap[2] = R_GetTexture(lightcubemap);
1696 m.pointer_texcoord3f[2] = vertex3f;
1697 m.texmatrix[2] = *matrix_modeltolight;
1699 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1700 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1702 GL_BlendFunc(GL_ONE, GL_ONE);
1704 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1706 // 2 3D combine path (Geforce3, original Radeon)
1707 memset(&m, 0, sizeof(m));
1708 m.pointer_vertex = vertex3f;
1709 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1711 m.pointer_texcoord3f[0] = vertex3f;
1712 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1714 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1715 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1717 m.tex[1] = R_GetTexture(basetexture);
1718 m.pointer_texcoord[1] = texcoord2f;
1719 GL_BlendFunc(GL_ONE, GL_ONE);
1721 else if (r_textureunits.integer >= 4 && lightcubemap)
1723 // 4 2D combine path (Geforce3, Radeon 8500)
1724 memset(&m, 0, sizeof(m));
1725 m.pointer_vertex = vertex3f;
1726 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1728 m.pointer_texcoord3f[0] = vertex3f;
1729 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1731 m.pointer_texcoord[0] = varray_texcoord2f[0];
1732 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1734 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1736 m.pointer_texcoord3f[1] = vertex3f;
1737 m.texmatrix[1] = *matrix_modeltoattenuationz;
1739 m.pointer_texcoord[1] = varray_texcoord2f[1];
1740 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1742 m.tex[2] = R_GetTexture(basetexture);
1743 m.pointer_texcoord[2] = texcoord2f;
1746 m.texcubemap[3] = R_GetTexture(lightcubemap);
1748 m.pointer_texcoord3f[3] = vertex3f;
1749 m.texmatrix[3] = *matrix_modeltolight;
1751 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1752 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1755 GL_BlendFunc(GL_ONE, GL_ONE);
1757 else if (r_textureunits.integer >= 3 && !lightcubemap)
1759 // 3 2D combine path (Geforce3, original Radeon)
1760 memset(&m, 0, sizeof(m));
1761 m.pointer_vertex = vertex3f;
1762 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1764 m.pointer_texcoord3f[0] = vertex3f;
1765 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1767 m.pointer_texcoord[0] = varray_texcoord2f[0];
1768 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1770 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1772 m.pointer_texcoord3f[1] = vertex3f;
1773 m.texmatrix[1] = *matrix_modeltoattenuationz;
1775 m.pointer_texcoord[1] = varray_texcoord2f[1];
1776 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1778 m.tex[2] = R_GetTexture(basetexture);
1779 m.pointer_texcoord[2] = texcoord2f;
1780 GL_BlendFunc(GL_ONE, GL_ONE);
1784 // 2/2/2 2D combine path (any dot3 card)
1785 memset(&m, 0, sizeof(m));
1786 m.pointer_vertex = vertex3f;
1787 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1789 m.pointer_texcoord3f[0] = vertex3f;
1790 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1792 m.pointer_texcoord[0] = varray_texcoord2f[0];
1793 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1795 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1797 m.pointer_texcoord3f[1] = vertex3f;
1798 m.texmatrix[1] = *matrix_modeltoattenuationz;
1800 m.pointer_texcoord[1] = varray_texcoord2f[1];
1801 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1804 GL_ColorMask(0,0,0,1);
1805 GL_BlendFunc(GL_ONE, GL_ZERO);
1806 GL_LockArrays(0, numverts);
1807 R_Mesh_Draw(numverts, numtriangles, elements);
1808 GL_LockArrays(0, 0);
1810 c_rt_lighttris += numtriangles;
1812 memset(&m, 0, sizeof(m));
1813 m.pointer_vertex = vertex3f;
1814 m.tex[0] = R_GetTexture(basetexture);
1815 m.pointer_texcoord[0] = texcoord2f;
1818 m.texcubemap[1] = R_GetTexture(lightcubemap);
1820 m.pointer_texcoord3f[1] = vertex3f;
1821 m.texmatrix[1] = *matrix_modeltolight;
1823 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1824 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1827 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1829 // this final code is shared
1831 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1832 VectorScale(lightcolor, colorscale, color2);
1833 GL_LockArrays(0, numverts);
1834 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1836 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1837 R_Mesh_Draw(numverts, numtriangles, elements);
1839 c_rt_lighttris += numtriangles;
1841 GL_LockArrays(0, 0);
1846 colorscale = diffusescale;
1847 // colorscale accounts for how much we multiply the brightness
1850 // mult is how many times the final pass of the lighting will be
1851 // performed to get more brightness than otherwise possible.
1853 // Limit mult to 64 for sanity sake.
1854 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1856 // 3/2 3D combine path (Geforce3, Radeon 8500)
1857 memset(&m, 0, sizeof(m));
1858 m.pointer_vertex = vertex3f;
1859 m.tex[0] = R_GetTexture(bumptexture);
1860 m.texcombinergb[0] = GL_REPLACE;
1861 m.pointer_texcoord[0] = texcoord2f;
1862 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1863 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1864 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1865 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1866 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1868 m.pointer_texcoord3f[2] = vertex3f;
1869 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1871 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1872 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1875 GL_ColorMask(0,0,0,1);
1876 GL_BlendFunc(GL_ONE, GL_ZERO);
1877 GL_LockArrays(0, numverts);
1878 R_Mesh_Draw(numverts, numtriangles, elements);
1879 GL_LockArrays(0, 0);
1881 c_rt_lighttris += numtriangles;
1883 memset(&m, 0, sizeof(m));
1884 m.pointer_vertex = vertex3f;
1885 m.tex[0] = R_GetTexture(basetexture);
1886 m.pointer_texcoord[0] = texcoord2f;
1889 m.texcubemap[1] = R_GetTexture(lightcubemap);
1891 m.pointer_texcoord3f[1] = vertex3f;
1892 m.texmatrix[1] = *matrix_modeltolight;
1894 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1895 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1898 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1900 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1902 // 1/2/2 3D combine path (original Radeon)
1903 memset(&m, 0, sizeof(m));
1904 m.pointer_vertex = vertex3f;
1905 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1907 m.pointer_texcoord3f[0] = vertex3f;
1908 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1910 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1911 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1914 GL_ColorMask(0,0,0,1);
1915 GL_BlendFunc(GL_ONE, GL_ZERO);
1916 GL_LockArrays(0, numverts);
1917 R_Mesh_Draw(numverts, numtriangles, elements);
1918 GL_LockArrays(0, 0);
1920 c_rt_lighttris += numtriangles;
1922 memset(&m, 0, sizeof(m));
1923 m.pointer_vertex = vertex3f;
1924 m.tex[0] = R_GetTexture(bumptexture);
1925 m.texcombinergb[0] = GL_REPLACE;
1926 m.pointer_texcoord[0] = texcoord2f;
1927 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1928 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1929 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1930 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1932 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1933 GL_LockArrays(0, numverts);
1934 R_Mesh_Draw(numverts, numtriangles, elements);
1935 GL_LockArrays(0, 0);
1937 c_rt_lighttris += numtriangles;
1939 memset(&m, 0, sizeof(m));
1940 m.pointer_vertex = vertex3f;
1941 m.tex[0] = R_GetTexture(basetexture);
1942 m.pointer_texcoord[0] = texcoord2f;
1945 m.texcubemap[1] = R_GetTexture(lightcubemap);
1947 m.pointer_texcoord3f[1] = vertex3f;
1948 m.texmatrix[1] = *matrix_modeltolight;
1950 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1951 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1954 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1956 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1958 // 2/2 3D combine path (original Radeon)
1959 memset(&m, 0, sizeof(m));
1960 m.pointer_vertex = vertex3f;
1961 m.tex[0] = R_GetTexture(bumptexture);
1962 m.texcombinergb[0] = GL_REPLACE;
1963 m.pointer_texcoord[0] = texcoord2f;
1964 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1965 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1966 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1967 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1969 GL_ColorMask(0,0,0,1);
1970 GL_BlendFunc(GL_ONE, GL_ZERO);
1971 GL_LockArrays(0, numverts);
1972 R_Mesh_Draw(numverts, numtriangles, elements);
1973 GL_LockArrays(0, 0);
1975 c_rt_lighttris += numtriangles;
1977 memset(&m, 0, sizeof(m));
1978 m.pointer_vertex = vertex3f;
1979 m.tex[0] = R_GetTexture(basetexture);
1980 m.pointer_texcoord[0] = texcoord2f;
1981 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1983 m.pointer_texcoord3f[1] = vertex3f;
1984 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1986 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1987 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1989 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1991 else if (r_textureunits.integer >= 4)
1993 // 4/2 2D combine path (Geforce3, Radeon 8500)
1994 memset(&m, 0, sizeof(m));
1995 m.pointer_vertex = vertex3f;
1996 m.tex[0] = R_GetTexture(bumptexture);
1997 m.texcombinergb[0] = GL_REPLACE;
1998 m.pointer_texcoord[0] = texcoord2f;
1999 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2000 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2001 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2002 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2003 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2005 m.pointer_texcoord3f[2] = vertex3f;
2006 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2008 m.pointer_texcoord[2] = varray_texcoord2f[2];
2009 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2011 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2013 m.pointer_texcoord3f[3] = vertex3f;
2014 m.texmatrix[3] = *matrix_modeltoattenuationz;
2016 m.pointer_texcoord[3] = varray_texcoord2f[3];
2017 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2020 GL_ColorMask(0,0,0,1);
2021 GL_BlendFunc(GL_ONE, GL_ZERO);
2022 GL_LockArrays(0, numverts);
2023 R_Mesh_Draw(numverts, numtriangles, elements);
2024 GL_LockArrays(0, 0);
2026 c_rt_lighttris += numtriangles;
2028 memset(&m, 0, sizeof(m));
2029 m.pointer_vertex = vertex3f;
2030 m.tex[0] = R_GetTexture(basetexture);
2031 m.pointer_texcoord[0] = texcoord2f;
2034 m.texcubemap[1] = R_GetTexture(lightcubemap);
2036 m.pointer_texcoord3f[1] = vertex3f;
2037 m.texmatrix[1] = *matrix_modeltolight;
2039 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2040 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2043 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2047 // 2/2/2 2D combine path (any dot3 card)
2048 memset(&m, 0, sizeof(m));
2049 m.pointer_vertex = vertex3f;
2050 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2052 m.pointer_texcoord3f[0] = vertex3f;
2053 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2055 m.pointer_texcoord[0] = varray_texcoord2f[0];
2056 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2058 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2060 m.pointer_texcoord3f[1] = vertex3f;
2061 m.texmatrix[1] = *matrix_modeltoattenuationz;
2063 m.pointer_texcoord[1] = varray_texcoord2f[1];
2064 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2067 GL_ColorMask(0,0,0,1);
2068 GL_BlendFunc(GL_ONE, GL_ZERO);
2069 GL_LockArrays(0, numverts);
2070 R_Mesh_Draw(numverts, numtriangles, elements);
2071 GL_LockArrays(0, 0);
2073 c_rt_lighttris += numtriangles;
2075 memset(&m, 0, sizeof(m));
2076 m.pointer_vertex = vertex3f;
2077 m.tex[0] = R_GetTexture(bumptexture);
2078 m.texcombinergb[0] = GL_REPLACE;
2079 m.pointer_texcoord[0] = texcoord2f;
2080 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2081 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2082 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2083 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2085 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2086 GL_LockArrays(0, numverts);
2087 R_Mesh_Draw(numverts, numtriangles, elements);
2088 GL_LockArrays(0, 0);
2090 c_rt_lighttris += numtriangles;
2092 memset(&m, 0, sizeof(m));
2093 m.pointer_vertex = vertex3f;
2094 m.tex[0] = R_GetTexture(basetexture);
2095 m.pointer_texcoord[0] = texcoord2f;
2098 m.texcubemap[1] = R_GetTexture(lightcubemap);
2100 m.pointer_texcoord3f[1] = vertex3f;
2101 m.texmatrix[1] = *matrix_modeltolight;
2103 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2104 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2107 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2109 // this final code is shared
2111 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2112 VectorScale(lightcolor, colorscale, color2);
2113 GL_LockArrays(0, numverts);
2114 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2116 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2117 R_Mesh_Draw(numverts, numtriangles, elements);
2119 c_rt_lighttris += numtriangles;
2121 GL_LockArrays(0, 0);
2123 if (specularscale && glosstexture != r_shadow_blankblacktexture)
2125 // FIXME: detect blendsquare!
2126 //if (gl_support_blendsquare)
2128 colorscale = specularscale;
2130 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2132 // 2/0/0/1/2 3D combine blendsquare path
2133 memset(&m, 0, sizeof(m));
2134 m.pointer_vertex = vertex3f;
2135 m.tex[0] = R_GetTexture(bumptexture);
2136 m.pointer_texcoord[0] = texcoord2f;
2137 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2138 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2139 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2140 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2142 GL_ColorMask(0,0,0,1);
2143 // this squares the result
2144 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2145 GL_LockArrays(0, numverts);
2146 R_Mesh_Draw(numverts, numtriangles, elements);
2147 GL_LockArrays(0, 0);
2149 c_rt_lighttris += numtriangles;
2151 memset(&m, 0, sizeof(m));
2152 m.pointer_vertex = vertex3f;
2154 GL_LockArrays(0, numverts);
2155 // square alpha in framebuffer a few times to make it shiny
2156 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2157 // these comments are a test run through this math for intensity 0.5
2158 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2159 // 0.25 * 0.25 = 0.0625 (this is another pass)
2160 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2161 R_Mesh_Draw(numverts, numtriangles, elements);
2163 c_rt_lighttris += numtriangles;
2164 R_Mesh_Draw(numverts, numtriangles, elements);
2166 c_rt_lighttris += numtriangles;
2167 GL_LockArrays(0, 0);
2169 memset(&m, 0, sizeof(m));
2170 m.pointer_vertex = vertex3f;
2171 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2173 m.pointer_texcoord3f[0] = vertex3f;
2174 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2176 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2177 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2180 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2181 GL_LockArrays(0, numverts);
2182 R_Mesh_Draw(numverts, numtriangles, elements);
2183 GL_LockArrays(0, 0);
2185 c_rt_lighttris += numtriangles;
2187 memset(&m, 0, sizeof(m));
2188 m.pointer_vertex = vertex3f;
2189 m.tex[0] = R_GetTexture(glosstexture);
2190 m.pointer_texcoord[0] = texcoord2f;
2193 m.texcubemap[1] = R_GetTexture(lightcubemap);
2195 m.pointer_texcoord3f[1] = vertex3f;
2196 m.texmatrix[1] = *matrix_modeltolight;
2198 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2199 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2202 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2204 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2206 // 2/0/0/2 3D combine blendsquare path
2207 memset(&m, 0, sizeof(m));
2208 m.pointer_vertex = vertex3f;
2209 m.tex[0] = R_GetTexture(bumptexture);
2210 m.pointer_texcoord[0] = texcoord2f;
2211 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2212 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2213 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2214 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2216 GL_ColorMask(0,0,0,1);
2217 // this squares the result
2218 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2219 GL_LockArrays(0, numverts);
2220 R_Mesh_Draw(numverts, numtriangles, elements);
2221 GL_LockArrays(0, 0);
2223 c_rt_lighttris += numtriangles;
2225 memset(&m, 0, sizeof(m));
2226 m.pointer_vertex = vertex3f;
2228 GL_LockArrays(0, numverts);
2229 // square alpha in framebuffer a few times to make it shiny
2230 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2231 // these comments are a test run through this math for intensity 0.5
2232 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2233 // 0.25 * 0.25 = 0.0625 (this is another pass)
2234 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2235 R_Mesh_Draw(numverts, numtriangles, elements);
2237 c_rt_lighttris += numtriangles;
2238 R_Mesh_Draw(numverts, numtriangles, elements);
2240 c_rt_lighttris += numtriangles;
2241 GL_LockArrays(0, 0);
2243 memset(&m, 0, sizeof(m));
2244 m.pointer_vertex = vertex3f;
2245 m.tex[0] = R_GetTexture(glosstexture);
2246 m.pointer_texcoord[0] = texcoord2f;
2247 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2249 m.pointer_texcoord3f[1] = vertex3f;
2250 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2252 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2253 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2255 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2259 // 2/0/0/2/2 2D combine blendsquare path
2260 memset(&m, 0, sizeof(m));
2261 m.pointer_vertex = vertex3f;
2262 m.tex[0] = R_GetTexture(bumptexture);
2263 m.pointer_texcoord[0] = texcoord2f;
2264 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2265 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2266 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2267 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2269 GL_ColorMask(0,0,0,1);
2270 // this squares the result
2271 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2272 GL_LockArrays(0, numverts);
2273 R_Mesh_Draw(numverts, numtriangles, elements);
2274 GL_LockArrays(0, 0);
2276 c_rt_lighttris += numtriangles;
2278 memset(&m, 0, sizeof(m));
2279 m.pointer_vertex = vertex3f;
2281 GL_LockArrays(0, numverts);
2282 // square alpha in framebuffer a few times to make it shiny
2283 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2284 // these comments are a test run through this math for intensity 0.5
2285 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2286 // 0.25 * 0.25 = 0.0625 (this is another pass)
2287 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2288 R_Mesh_Draw(numverts, numtriangles, elements);
2290 c_rt_lighttris += numtriangles;
2291 R_Mesh_Draw(numverts, numtriangles, elements);
2293 c_rt_lighttris += numtriangles;
2294 GL_LockArrays(0, 0);
2296 memset(&m, 0, sizeof(m));
2297 m.pointer_vertex = vertex3f;
2298 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2300 m.pointer_texcoord3f[0] = vertex3f;
2301 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2303 m.pointer_texcoord[0] = varray_texcoord2f[0];
2304 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2306 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2308 m.pointer_texcoord3f[1] = vertex3f;
2309 m.texmatrix[1] = *matrix_modeltoattenuationz;
2311 m.pointer_texcoord[1] = varray_texcoord2f[1];
2312 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2315 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2316 GL_LockArrays(0, numverts);
2317 R_Mesh_Draw(numverts, numtriangles, elements);
2318 GL_LockArrays(0, 0);
2320 c_rt_lighttris += numtriangles;
2322 memset(&m, 0, sizeof(m));
2323 m.pointer_vertex = vertex3f;
2324 m.tex[0] = R_GetTexture(glosstexture);
2325 m.pointer_texcoord[0] = texcoord2f;
2328 m.texcubemap[1] = R_GetTexture(lightcubemap);
2330 m.pointer_texcoord3f[1] = vertex3f;
2331 m.texmatrix[1] = *matrix_modeltolight;
2333 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2334 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2337 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2340 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2341 VectorScale(lightcolor, colorscale, color2);
2342 GL_LockArrays(0, numverts);
2343 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2345 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2346 R_Mesh_Draw(numverts, numtriangles, elements);
2348 c_rt_lighttris += numtriangles;
2350 GL_LockArrays(0, 0);
2358 GL_BlendFunc(GL_ONE, GL_ONE);
2359 VectorScale(lightcolor, ambientscale, color2);
2360 memset(&m, 0, sizeof(m));
2361 m.pointer_vertex = vertex3f;
2362 m.tex[0] = R_GetTexture(basetexture);
2363 m.pointer_texcoord[0] = texcoord2f;
2364 if (r_textureunits.integer >= 2)
2367 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2369 m.pointer_texcoord3f[1] = vertex3f;
2370 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2372 m.pointer_texcoord[1] = varray_texcoord2f[1];
2373 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2375 if (r_textureunits.integer >= 3)
2377 // Geforce3/Radeon class but not using dot3
2378 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2380 m.pointer_texcoord3f[2] = vertex3f;
2381 m.texmatrix[2] = *matrix_modeltoattenuationz;
2383 m.pointer_texcoord[2] = varray_texcoord2f[2];
2384 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2388 if (r_textureunits.integer >= 3)
2389 m.pointer_color = NULL;
2391 m.pointer_color = varray_color4f;
2393 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2395 color[0] = bound(0, color2[0], 1);
2396 color[1] = bound(0, color2[1], 1);
2397 color[2] = bound(0, color2[2], 1);
2398 if (r_textureunits.integer >= 3)
2399 GL_Color(color[0], color[1], color[2], 1);
2400 else if (r_textureunits.integer >= 2)
2401 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2403 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2404 GL_LockArrays(0, numverts);
2405 R_Mesh_Draw(numverts, numtriangles, elements);
2406 GL_LockArrays(0, 0);
2408 c_rt_lighttris += numtriangles;
2413 GL_BlendFunc(GL_ONE, GL_ONE);
2414 VectorScale(lightcolor, diffusescale, color2);
2415 memset(&m, 0, sizeof(m));
2416 m.pointer_vertex = vertex3f;
2417 m.pointer_color = varray_color4f;
2418 m.tex[0] = R_GetTexture(basetexture);
2419 m.pointer_texcoord[0] = texcoord2f;
2420 if (r_textureunits.integer >= 2)
2423 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2425 m.pointer_texcoord3f[1] = vertex3f;
2426 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2428 m.pointer_texcoord[1] = varray_texcoord2f[1];
2429 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2431 if (r_textureunits.integer >= 3)
2433 // Geforce3/Radeon class but not using dot3
2434 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2436 m.pointer_texcoord3f[2] = vertex3f;
2437 m.texmatrix[2] = *matrix_modeltoattenuationz;
2439 m.pointer_texcoord[2] = varray_texcoord2f[2];
2440 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2445 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2447 color[0] = bound(0, color2[0], 1);
2448 color[1] = bound(0, color2[1], 1);
2449 color[2] = bound(0, color2[2], 1);
2450 if (r_textureunits.integer >= 3)
2451 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2452 else if (r_textureunits.integer >= 2)
2453 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2455 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2456 GL_LockArrays(0, numverts);
2457 R_Mesh_Draw(numverts, numtriangles, elements);
2458 GL_LockArrays(0, 0);
2460 c_rt_lighttris += numtriangles;
2466 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2470 R_RTLight_Uncompile(rtlight);
2471 memset(rtlight, 0, sizeof(*rtlight));
2473 VectorCopy(light->origin, rtlight->shadoworigin);
2474 VectorCopy(light->color, rtlight->color);
2475 rtlight->radius = light->radius;
2476 //rtlight->cullradius = rtlight->radius;
2477 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2478 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2479 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2480 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2481 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2482 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2483 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2484 rtlight->cubemapname[0] = 0;
2485 if (light->cubemapname[0])
2486 strcpy(rtlight->cubemapname, light->cubemapname);
2487 else if (light->cubemapnum > 0)
2488 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2489 rtlight->shadow = light->shadow;
2490 rtlight->corona = light->corona;
2491 rtlight->style = light->style;
2492 rtlight->isstatic = isstatic;
2493 rtlight->coronasizescale = light->coronasizescale;
2494 rtlight->ambientscale = light->ambientscale;
2495 rtlight->diffusescale = light->diffusescale;
2496 rtlight->specularscale = light->specularscale;
2497 rtlight->flags = light->flags;
2498 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2499 // ConcatScale won't work here because this needs to scale rotate and
2500 // translate, not just rotate
2501 scale = 1.0f / rtlight->radius;
2502 for (k = 0;k < 3;k++)
2503 for (j = 0;j < 4;j++)
2504 rtlight->matrix_worldtolight.m[k][j] *= scale;
2505 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2506 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2508 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2509 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2510 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2511 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2514 // compiles rtlight geometry
2515 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2516 void R_RTLight_Compile(rtlight_t *rtlight)
2518 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2519 entity_render_t *ent = &cl_entities[0].render;
2520 model_t *model = ent->model;
2522 // compile the light
2523 rtlight->compiled = true;
2524 rtlight->static_numclusters = 0;
2525 rtlight->static_numclusterpvsbytes = 0;
2526 rtlight->static_clusterlist = NULL;
2527 rtlight->static_clusterpvs = NULL;
2528 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2529 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2530 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2531 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2532 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2533 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2535 if (model && model->GetLightInfo)
2537 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2538 r_shadow_compilingrtlight = rtlight;
2539 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2540 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2541 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);
2542 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2543 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2546 rtlight->static_numclusters = numclusters;
2547 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2548 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2549 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2551 if (model->DrawShadowVolume && rtlight->shadow)
2553 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2554 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2555 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2557 if (model->DrawLight)
2559 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2560 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);
2561 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2563 // switch back to rendering when DrawShadowVolume or DrawLight is called
2564 r_shadow_compilingrtlight = NULL;
2568 // use smallest available cullradius - box radius or light radius
2569 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2570 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2574 if (rtlight->static_meshchain_shadow)
2577 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2580 shadowtris += mesh->numtriangles;
2586 if (rtlight->static_meshchain_light)
2589 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2592 lighttris += mesh->numtriangles;
2596 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);
2599 void R_RTLight_Uncompile(rtlight_t *rtlight)
2601 if (rtlight->compiled)
2603 if (rtlight->static_meshchain_shadow)
2604 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2605 rtlight->static_meshchain_shadow = NULL;
2606 if (rtlight->static_meshchain_light)
2607 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2608 rtlight->static_meshchain_light = NULL;
2609 if (rtlight->static_clusterlist)
2610 Mem_Free(rtlight->static_clusterlist);
2611 rtlight->static_clusterlist = NULL;
2612 if (rtlight->static_clusterpvs)
2613 Mem_Free(rtlight->static_clusterpvs);
2614 rtlight->static_clusterpvs = NULL;
2615 rtlight->static_numclusters = 0;
2616 rtlight->static_numclusterpvsbytes = 0;
2617 rtlight->compiled = false;
2621 void R_Shadow_UncompileWorldLights(void)
2624 for (light = r_shadow_worldlightchain;light;light = light->next)
2625 R_RTLight_Uncompile(&light->rtlight);
2628 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2630 int i, shadow, usestencil;
2631 entity_render_t *ent;
2633 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2634 rtexture_t *cubemaptexture;
2635 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2636 int numclusters, numsurfaces;
2637 int *clusterlist, *surfacelist;
2639 vec3_t cullmins, cullmaxs;
2643 // skip lights that don't light (corona only lights)
2644 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2647 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2648 VectorScale(rtlight->color, f, lightcolor);
2649 if (VectorLength2(lightcolor) < 0.01)
2652 if (rtlight->selected)
2654 f = 2 + sin(realtime * M_PI * 4.0);
2655 VectorScale(lightcolor, f, lightcolor);
2659 // loading is done before visibility checks because loading should happen
2660 // all at once at the start of a level, not when it stalls gameplay.
2661 // (especially important to benchmarks)
2662 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2663 R_RTLight_Compile(rtlight);
2664 if (rtlight->cubemapname[0])
2665 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2667 cubemaptexture = NULL;
2669 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2670 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2671 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2672 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2673 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2674 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2675 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2682 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2684 // compiled light, world available and can receive realtime lighting
2685 // retrieve cluster information
2686 numclusters = rtlight->static_numclusters;
2687 clusterlist = rtlight->static_clusterlist;
2688 clusterpvs = rtlight->static_clusterpvs;
2689 VectorCopy(rtlight->cullmins, cullmins);
2690 VectorCopy(rtlight->cullmaxs, cullmaxs);
2692 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2694 // dynamic light, world available and can receive realtime lighting
2695 // if the light box is offscreen, skip it right away
2696 if (R_CullBox(cullmins, cullmaxs))
2698 // calculate lit surfaces and clusters
2699 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2700 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2701 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);
2702 clusterlist = r_shadow_buffer_clusterlist;
2703 clusterpvs = r_shadow_buffer_clusterpvs;
2704 surfacelist = r_shadow_buffer_surfacelist;
2706 // if the reduced cluster bounds are offscreen, skip it
2707 if (R_CullBox(cullmins, cullmaxs))
2709 // check if light is illuminating any visible clusters
2712 for (i = 0;i < numclusters;i++)
2713 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2715 if (i == numclusters)
2718 // set up a scissor rectangle for this light
2719 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2722 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2725 if (shadow && (gl_stencil || visiblevolumes))
2727 if (!visiblevolumes)
2729 R_Shadow_Stage_ShadowVolumes();
2732 ent = &cl_entities[0].render;
2733 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2735 memset(&m, 0, sizeof(m));
2736 R_Mesh_Matrix(&ent->matrix);
2737 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2739 m.pointer_vertex = mesh->vertex3f;
2741 GL_LockArrays(0, mesh->numverts);
2742 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2744 // increment stencil if backface is behind depthbuffer
2745 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2746 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2747 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2748 c_rtcached_shadowmeshes++;
2749 c_rtcached_shadowtris += mesh->numtriangles;
2750 // decrement stencil if frontface is behind depthbuffer
2751 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2752 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2754 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2755 c_rtcached_shadowmeshes++;
2756 c_rtcached_shadowtris += mesh->numtriangles;
2757 GL_LockArrays(0, 0);
2760 else if (numsurfaces)
2762 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2763 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2765 if (r_drawentities.integer)
2767 for (i = 0;i < r_refdef.numentities;i++)
2769 ent = r_refdef.entities[i];
2771 if (r_shadow_cull.integer)
2773 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2775 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2778 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2780 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2781 // light emitting entities should not cast their own shadow
2782 if (VectorLength2(relativelightorigin) < 0.1)
2784 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2789 if (!visiblevolumes)
2791 R_Shadow_Stage_Light(usestencil);
2793 ent = &cl_entities[0].render;
2794 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2796 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2797 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2798 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2799 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2800 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2801 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2802 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2803 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2804 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2806 R_Mesh_Matrix(&ent->matrix);
2807 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2808 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);
2811 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2813 if (r_drawentities.integer)
2815 for (i = 0;i < r_refdef.numentities;i++)
2817 ent = r_refdef.entities[i];
2818 // can't draw transparent entity lighting here because
2819 // transparent meshes are deferred for later
2820 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)
2822 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2823 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2824 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2825 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2826 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2827 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2828 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2829 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2830 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);
2837 void R_ShadowVolumeLighting(int visiblevolumes)
2843 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2844 R_Shadow_EditLights_Reload_f();
2848 memset(&m, 0, sizeof(m));
2851 GL_BlendFunc(GL_ONE, GL_ONE);
2852 GL_DepthMask(false);
2853 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2854 qglDisable(GL_CULL_FACE);
2855 GL_Color(0.0, 0.0125, 0.1, 1);
2858 R_Shadow_Stage_Begin();
2859 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2860 if (r_shadow_debuglight.integer >= 0)
2862 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2863 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2864 R_DrawRTLight(&light->rtlight, visiblevolumes);
2867 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2868 if (light->flags & flag)
2869 R_DrawRTLight(&light->rtlight, visiblevolumes);
2871 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2872 R_DrawRTLight(&light->rtlight, visiblevolumes);
2876 qglEnable(GL_CULL_FACE);
2877 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2880 R_Shadow_Stage_End();
2883 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2884 typedef struct suffixinfo_s
2887 qboolean flipx, flipy, flipdiagonal;
2890 static suffixinfo_t suffix[3][6] =
2893 {"px", false, false, false},
2894 {"nx", false, false, false},
2895 {"py", false, false, false},
2896 {"ny", false, false, false},
2897 {"pz", false, false, false},
2898 {"nz", false, false, false}
2901 {"posx", false, false, false},
2902 {"negx", false, false, false},
2903 {"posy", false, false, false},
2904 {"negy", false, false, false},
2905 {"posz", false, false, false},
2906 {"negz", false, false, false}
2909 {"rt", true, false, true},
2910 {"lf", false, true, true},
2911 {"ft", true, true, false},
2912 {"bk", false, false, false},
2913 {"up", true, false, true},
2914 {"dn", true, false, true}
2918 static int componentorder[4] = {0, 1, 2, 3};
2920 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2922 int i, j, cubemapsize;
2923 qbyte *cubemappixels, *image_rgba;
2924 rtexture_t *cubemaptexture;
2926 // must start 0 so the first loadimagepixels has no requested width/height
2928 cubemappixels = NULL;
2929 cubemaptexture = NULL;
2930 // keep trying different suffix groups (posx, px, rt) until one loads
2931 for (j = 0;j < 3 && !cubemappixels;j++)
2933 // load the 6 images in the suffix group
2934 for (i = 0;i < 6;i++)
2936 // generate an image name based on the base and and suffix
2937 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2939 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2941 // an image loaded, make sure width and height are equal
2942 if (image_width == image_height)
2944 // if this is the first image to load successfully, allocate the cubemap memory
2945 if (!cubemappixels && image_width >= 1)
2947 cubemapsize = image_width;
2948 // note this clears to black, so unavailable sides are black
2949 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2951 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2953 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);
2956 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2958 Mem_Free(image_rgba);
2962 // if a cubemap loaded, upload it
2965 if (!r_shadow_filters_texturepool)
2966 r_shadow_filters_texturepool = R_AllocTexturePool();
2967 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2968 Mem_Free(cubemappixels);
2972 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2973 for (j = 0;j < 3;j++)
2974 for (i = 0;i < 6;i++)
2975 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2976 Con_Print(" and was unable to find any of them.\n");
2978 return cubemaptexture;
2981 rtexture_t *R_Shadow_Cubemap(const char *basename)
2984 for (i = 0;i < numcubemaps;i++)
2985 if (!strcasecmp(cubemaps[i].basename, basename))
2986 return cubemaps[i].texture;
2987 if (i >= MAX_CUBEMAPS)
2990 strcpy(cubemaps[i].basename, basename);
2991 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2992 return cubemaps[i].texture;
2995 void R_Shadow_FreeCubemaps(void)
2998 R_FreeTexturePool(&r_shadow_filters_texturepool);
3001 dlight_t *R_Shadow_NewWorldLight(void)
3004 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3005 light->next = r_shadow_worldlightchain;
3006 r_shadow_worldlightchain = light;
3010 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)
3012 VectorCopy(origin, light->origin);
3013 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3014 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3015 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3016 light->color[0] = max(color[0], 0);
3017 light->color[1] = max(color[1], 0);
3018 light->color[2] = max(color[2], 0);
3019 light->radius = max(radius, 0);
3020 light->style = style;
3021 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3023 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3026 light->shadow = shadowenable;
3027 light->corona = corona;
3030 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
3031 light->coronasizescale = coronasizescale;
3032 light->ambientscale = ambientscale;
3033 light->diffusescale = diffusescale;
3034 light->specularscale = specularscale;
3035 light->flags = flags;
3036 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3038 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3041 void R_Shadow_FreeWorldLight(dlight_t *light)
3043 dlight_t **lightpointer;
3044 R_RTLight_Uncompile(&light->rtlight);
3045 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3046 if (*lightpointer != light)
3047 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3048 *lightpointer = light->next;
3052 void R_Shadow_ClearWorldLights(void)
3054 while (r_shadow_worldlightchain)
3055 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3056 r_shadow_selectedlight = NULL;
3057 R_Shadow_FreeCubemaps();
3060 void R_Shadow_SelectLight(dlight_t *light)
3062 if (r_shadow_selectedlight)
3063 r_shadow_selectedlight->selected = false;
3064 r_shadow_selectedlight = light;
3065 if (r_shadow_selectedlight)
3066 r_shadow_selectedlight->selected = true;
3069 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3071 float scale = r_editlights_cursorgrid.value * 0.5f;
3072 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);
3075 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3078 const dlight_t *light;
3081 if (light->selected)
3082 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3085 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);
3088 void R_Shadow_DrawLightSprites(void)
3094 for (i = 0;i < 5;i++)
3096 lighttextures[i] = NULL;
3097 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3098 lighttextures[i] = pic->tex;
3101 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3102 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3103 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3106 void R_Shadow_SelectLightInView(void)
3108 float bestrating, rating, temp[3];
3109 dlight_t *best, *light;
3112 for (light = r_shadow_worldlightchain;light;light = light->next)
3114 VectorSubtract(light->origin, r_vieworigin, temp);
3115 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3118 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3119 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3121 bestrating = rating;
3126 R_Shadow_SelectLight(best);
3129 void R_Shadow_LoadWorldLights(void)
3131 int n, a, style, shadow, flags;
3132 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
3133 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3134 if (r_refdef.worldmodel == NULL)
3136 Con_Print("No map loaded.\n");
3139 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3140 strlcat (name, ".rtlights", sizeof (name));
3141 lightsstring = FS_LoadFile(name, tempmempool, false);
3151 for (;COM_Parse(t, true) && strcmp(
3152 if (COM_Parse(t, true))
3154 if (com_token[0] == '!')
3157 origin[0] = atof(com_token+1);
3160 origin[0] = atof(com_token);
3165 while (*s && *s != '\n')
3171 // check for modifier flags
3177 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);
3179 flags = LIGHTFLAG_REALTIMEMODE;
3187 coronasizescale = 0.25f;
3189 VectorClear(angles);
3192 if (a < 9 || !strcmp(cubemapname, "\"\""))
3194 // remove quotes on cubemapname
3195 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3197 cubemapname[strlen(cubemapname)-1] = 0;
3198 strcpy(cubemapname, cubemapname + 1);
3203 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);
3206 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3207 radius *= r_editlights_rtlightssizescale.value;
3208 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3213 Con_Printf("invalid rtlights file \"%s\"\n", name);
3214 Mem_Free(lightsstring);
3218 void R_Shadow_SaveWorldLights(void)
3221 int bufchars, bufmaxchars;
3223 char name[MAX_QPATH];
3225 if (!r_shadow_worldlightchain)
3227 if (r_refdef.worldmodel == NULL)
3229 Con_Print("No map loaded.\n");
3232 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3233 strlcat (name, ".rtlights", sizeof (name));
3234 bufchars = bufmaxchars = 0;
3236 for (light = r_shadow_worldlightchain;light;light = light->next)
3238 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3239 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);
3240 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3241 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]);
3243 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);
3244 if (bufchars + (int) strlen(line) > bufmaxchars)
3246 bufmaxchars = bufchars + strlen(line) + 2048;
3248 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3252 memcpy(buf, oldbuf, bufchars);
3258 memcpy(buf + bufchars, line, strlen(line));
3259 bufchars += strlen(line);
3263 FS_WriteFile(name, buf, bufchars);
3268 void R_Shadow_LoadLightsFile(void)
3271 char name[MAX_QPATH], *lightsstring, *s, *t;
3272 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3273 if (r_refdef.worldmodel == NULL)
3275 Con_Print("No map loaded.\n");
3278 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3279 strlcat (name, ".lights", sizeof (name));
3280 lightsstring = FS_LoadFile(name, tempmempool, false);
3288 while (*s && *s != '\n')
3293 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);
3297 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);
3300 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3301 radius = bound(15, radius, 4096);
3302 VectorScale(color, (2.0f / (8388608.0f)), color);
3303 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3308 Con_Printf("invalid lights file \"%s\"\n", name);
3309 Mem_Free(lightsstring);
3313 // tyrlite/hmap2 light types in the delay field
3314 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3316 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3318 int entnum, style, islight, skin, pflags, effects, type, n;
3321 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3322 char key[256], value[1024];
3324 if (r_refdef.worldmodel == NULL)
3326 Con_Print("No map loaded.\n");
3329 // try to load a .ent file first
3330 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3331 strlcat (key, ".ent", sizeof (key));
3332 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3333 // and if that is not found, fall back to the bsp file entity string
3335 data = r_refdef.worldmodel->brush.entities;
3338 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3340 type = LIGHTTYPE_MINUSX;
3341 origin[0] = origin[1] = origin[2] = 0;
3342 originhack[0] = originhack[1] = originhack[2] = 0;
3343 angles[0] = angles[1] = angles[2] = 0;
3344 color[0] = color[1] = color[2] = 1;
3345 light[0] = light[1] = light[2] = 1;light[3] = 300;
3346 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3356 if (!COM_ParseToken(&data, false))
3358 if (com_token[0] == '}')
3359 break; // end of entity
3360 if (com_token[0] == '_')
3361 strcpy(key, com_token + 1);
3363 strcpy(key, com_token);
3364 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3365 key[strlen(key)-1] = 0;
3366 if (!COM_ParseToken(&data, false))
3368 strcpy(value, com_token);
3370 // now that we have the key pair worked out...
3371 if (!strcmp("light", key))
3373 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3377 light[0] = vec[0] * (1.0f / 256.0f);
3378 light[1] = vec[0] * (1.0f / 256.0f);
3379 light[2] = vec[0] * (1.0f / 256.0f);
3385 light[0] = vec[0] * (1.0f / 255.0f);
3386 light[1] = vec[1] * (1.0f / 255.0f);
3387 light[2] = vec[2] * (1.0f / 255.0f);
3391 else if (!strcmp("delay", key))
3393 else if (!strcmp("origin", key))
3394 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3395 else if (!strcmp("angle", key))
3396 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3397 else if (!strcmp("angles", key))
3398 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3399 else if (!strcmp("color", key))
3400 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3401 else if (!strcmp("wait", key))
3402 fadescale = atof(value);
3403 else if (!strcmp("classname", key))
3405 if (!strncmp(value, "light", 5))
3408 if (!strcmp(value, "light_fluoro"))
3413 overridecolor[0] = 1;
3414 overridecolor[1] = 1;
3415 overridecolor[2] = 1;
3417 if (!strcmp(value, "light_fluorospark"))
3422 overridecolor[0] = 1;
3423 overridecolor[1] = 1;
3424 overridecolor[2] = 1;
3426 if (!strcmp(value, "light_globe"))
3431 overridecolor[0] = 1;
3432 overridecolor[1] = 0.8;
3433 overridecolor[2] = 0.4;
3435 if (!strcmp(value, "light_flame_large_yellow"))
3440 overridecolor[0] = 1;
3441 overridecolor[1] = 0.5;
3442 overridecolor[2] = 0.1;
3444 if (!strcmp(value, "light_flame_small_yellow"))
3449 overridecolor[0] = 1;
3450 overridecolor[1] = 0.5;
3451 overridecolor[2] = 0.1;
3453 if (!strcmp(value, "light_torch_small_white"))
3458 overridecolor[0] = 1;
3459 overridecolor[1] = 0.5;
3460 overridecolor[2] = 0.1;
3462 if (!strcmp(value, "light_torch_small_walltorch"))
3467 overridecolor[0] = 1;
3468 overridecolor[1] = 0.5;
3469 overridecolor[2] = 0.1;
3473 else if (!strcmp("style", key))
3474 style = atoi(value);
3475 else if (r_refdef.worldmodel->type == mod_brushq3)
3477 if (!strcmp("scale", key))
3478 lightscale = atof(value);
3479 if (!strcmp("fade", key))
3480 fadescale = atof(value);
3482 else if (!strcmp("skin", key))
3483 skin = (int)atof(value);
3484 else if (!strcmp("pflags", key))
3485 pflags = (int)atof(value);
3486 else if (!strcmp("effects", key))
3487 effects = (int)atof(value);
3491 if (lightscale <= 0)
3495 if (color[0] == color[1] && color[0] == color[2])
3497 color[0] *= overridecolor[0];
3498 color[1] *= overridecolor[1];
3499 color[2] *= overridecolor[2];
3501 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3502 color[0] = color[0] * light[0];
3503 color[1] = color[1] * light[1];
3504 color[2] = color[2] * light[2];
3507 case LIGHTTYPE_MINUSX:
3509 case LIGHTTYPE_RECIPX:
3511 VectorScale(color, (1.0f / 16.0f), color);
3513 case LIGHTTYPE_RECIPXX:
3515 VectorScale(color, (1.0f / 16.0f), color);
3518 case LIGHTTYPE_NONE:
3522 case LIGHTTYPE_MINUSXX:
3525 VectorAdd(origin, originhack, origin);
3527 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);
3530 Mem_Free(entfiledata);
3534 void R_Shadow_SetCursorLocationForView(void)
3536 vec_t dist, push, frac;
3537 vec3_t dest, endpos, normal;
3538 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3539 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3542 dist = frac * r_editlights_cursordistance.value;
3543 push = r_editlights_cursorpushback.value;
3547 VectorMA(endpos, push, r_viewforward, endpos);
3548 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3550 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3551 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3552 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3555 void R_Shadow_UpdateWorldLightSelection(void)
3557 if (r_editlights.integer)
3559 R_Shadow_SetCursorLocationForView();
3560 R_Shadow_SelectLightInView();
3561 R_Shadow_DrawLightSprites();
3564 R_Shadow_SelectLight(NULL);
3567 void R_Shadow_EditLights_Clear_f(void)
3569 R_Shadow_ClearWorldLights();
3572 void R_Shadow_EditLights_Reload_f(void)
3574 if (!r_refdef.worldmodel)
3576 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3577 R_Shadow_ClearWorldLights();
3578 R_Shadow_LoadWorldLights();
3579 if (r_shadow_worldlightchain == NULL)
3581 R_Shadow_LoadLightsFile();
3582 if (r_shadow_worldlightchain == NULL)
3583 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3587 void R_Shadow_EditLights_Save_f(void)
3589 if (!r_refdef.worldmodel)
3591 R_Shadow_SaveWorldLights();
3594 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3596 R_Shadow_ClearWorldLights();
3597 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3600 void R_Shadow_EditLights_ImportLightsFile_f(void)
3602 R_Shadow_ClearWorldLights();
3603 R_Shadow_LoadLightsFile();
3606 void R_Shadow_EditLights_Spawn_f(void)
3609 if (!r_editlights.integer)
3611 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3614 if (Cmd_Argc() != 1)
3616 Con_Print("r_editlights_spawn does not take parameters\n");
3619 color[0] = color[1] = color[2] = 1;
3620 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3623 void R_Shadow_EditLights_Edit_f(void)
3625 vec3_t origin, angles, color;
3626 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3627 int style, shadows, flags, normalmode, realtimemode;
3628 char cubemapname[1024];
3629 if (!r_editlights.integer)
3631 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3634 if (!r_shadow_selectedlight)
3636 Con_Print("No selected light.\n");
3639 VectorCopy(r_shadow_selectedlight->origin, origin);
3640 VectorCopy(r_shadow_selectedlight->angles, angles);
3641 VectorCopy(r_shadow_selectedlight->color, color);
3642 radius = r_shadow_selectedlight->radius;
3643 style = r_shadow_selectedlight->style;
3644 if (r_shadow_selectedlight->cubemapname)
3645 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3648 shadows = r_shadow_selectedlight->shadow;
3649 corona = r_shadow_selectedlight->corona;
3650 coronasizescale = r_shadow_selectedlight->coronasizescale;
3651 ambientscale = r_shadow_selectedlight->ambientscale;
3652 diffusescale = r_shadow_selectedlight->diffusescale;
3653 specularscale = r_shadow_selectedlight->specularscale;
3654 flags = r_shadow_selectedlight->flags;
3655 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3656 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3657 if (!strcmp(Cmd_Argv(1), "origin"))
3659 if (Cmd_Argc() != 5)
3661 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3664 origin[0] = atof(Cmd_Argv(2));
3665 origin[1] = atof(Cmd_Argv(3));
3666 origin[2] = atof(Cmd_Argv(4));
3668 else if (!strcmp(Cmd_Argv(1), "originx"))
3670 if (Cmd_Argc() != 3)
3672 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3675 origin[0] = atof(Cmd_Argv(2));
3677 else if (!strcmp(Cmd_Argv(1), "originy"))
3679 if (Cmd_Argc() != 3)
3681 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3684 origin[1] = atof(Cmd_Argv(2));
3686 else if (!strcmp(Cmd_Argv(1), "originz"))
3688 if (Cmd_Argc() != 3)
3690 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3693 origin[2] = atof(Cmd_Argv(2));
3695 else if (!strcmp(Cmd_Argv(1), "move"))
3697 if (Cmd_Argc() != 5)
3699 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3702 origin[0] += atof(Cmd_Argv(2));
3703 origin[1] += atof(Cmd_Argv(3));
3704 origin[2] += atof(Cmd_Argv(4));
3706 else if (!strcmp(Cmd_Argv(1), "movex"))
3708 if (Cmd_Argc() != 3)
3710 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3713 origin[0] += atof(Cmd_Argv(2));
3715 else if (!strcmp(Cmd_Argv(1), "movey"))
3717 if (Cmd_Argc() != 3)
3719 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3722 origin[1] += atof(Cmd_Argv(2));
3724 else if (!strcmp(Cmd_Argv(1), "movez"))
3726 if (Cmd_Argc() != 3)
3728 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3731 origin[2] += atof(Cmd_Argv(2));
3733 else if (!strcmp(Cmd_Argv(1), "angles"))
3735 if (Cmd_Argc() != 5)
3737 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3740 angles[0] = atof(Cmd_Argv(2));
3741 angles[1] = atof(Cmd_Argv(3));
3742 angles[2] = atof(Cmd_Argv(4));
3744 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3746 if (Cmd_Argc() != 3)
3748 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3751 angles[0] = atof(Cmd_Argv(2));
3753 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3755 if (Cmd_Argc() != 3)
3757 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3760 angles[1] = atof(Cmd_Argv(2));
3762 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3764 if (Cmd_Argc() != 3)
3766 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3769 angles[2] = atof(Cmd_Argv(2));
3771 else if (!strcmp(Cmd_Argv(1), "color"))
3773 if (Cmd_Argc() != 5)
3775 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3778 color[0] = atof(Cmd_Argv(2));
3779 color[1] = atof(Cmd_Argv(3));
3780 color[2] = atof(Cmd_Argv(4));
3782 else if (!strcmp(Cmd_Argv(1), "radius"))
3784 if (Cmd_Argc() != 3)
3786 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3789 radius = atof(Cmd_Argv(2));
3791 else if (!strcmp(Cmd_Argv(1), "style"))
3793 if (Cmd_Argc() != 3)
3795 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3798 style = atoi(Cmd_Argv(2));
3800 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3804 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3807 if (Cmd_Argc() == 3)
3808 strcpy(cubemapname, Cmd_Argv(2));
3812 else if (!strcmp(Cmd_Argv(1), "shadows"))
3814 if (Cmd_Argc() != 3)
3816 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3819 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3821 else if (!strcmp(Cmd_Argv(1), "corona"))
3823 if (Cmd_Argc() != 3)
3825 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3828 corona = atof(Cmd_Argv(2));
3830 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3832 if (Cmd_Argc() != 3)
3834 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3837 coronasizescale = atof(Cmd_Argv(2));
3839 else if (!strcmp(Cmd_Argv(1), "ambient"))
3841 if (Cmd_Argc() != 3)
3843 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3846 ambientscale = atof(Cmd_Argv(2));
3848 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3850 if (Cmd_Argc() != 3)
3852 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3855 diffusescale = atof(Cmd_Argv(2));
3857 else if (!strcmp(Cmd_Argv(1), "specular"))
3859 if (Cmd_Argc() != 3)
3861 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3864 specularscale = atof(Cmd_Argv(2));
3866 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3868 if (Cmd_Argc() != 3)
3870 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3873 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3875 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3877 if (Cmd_Argc() != 3)
3879 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3882 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3886 Con_Print("usage: r_editlights_edit [property] [value]\n");
3887 Con_Print("Selected light's properties:\n");
3888 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3889 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3890 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3891 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3892 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3893 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3894 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3895 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3896 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3897 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3898 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3899 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3900 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3901 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3904 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3905 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3908 void R_Shadow_EditLights_EditAll_f(void)
3912 if (!r_editlights.integer)
3914 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3918 for (light = r_shadow_worldlightchain;light;light = light->next)
3920 R_Shadow_SelectLight(light);
3921 R_Shadow_EditLights_Edit_f();
3925 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3927 int lightnumber, lightcount;
3931 if (!r_editlights.integer)
3937 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3938 if (light == r_shadow_selectedlight)
3939 lightnumber = lightcount;
3940 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;
3941 if (r_shadow_selectedlight == NULL)
3943 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3944 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;
3945 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;
3946 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;
3947 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3948 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3949 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3950 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;
3951 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3952 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3953 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3954 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3955 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3956 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;
3957 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;
3960 void R_Shadow_EditLights_ToggleShadow_f(void)
3962 if (!r_editlights.integer)
3964 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3967 if (!r_shadow_selectedlight)
3969 Con_Print("No selected light.\n");
3972 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);
3975 void R_Shadow_EditLights_ToggleCorona_f(void)
3977 if (!r_editlights.integer)
3979 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3982 if (!r_shadow_selectedlight)
3984 Con_Print("No selected light.\n");
3987 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);
3990 void R_Shadow_EditLights_Remove_f(void)
3992 if (!r_editlights.integer)
3994 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3997 if (!r_shadow_selectedlight)
3999 Con_Print("No selected light.\n");
4002 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4003 r_shadow_selectedlight = NULL;
4006 void R_Shadow_EditLights_Help_f(void)
4009 "Documentation on r_editlights system:\n"
4011 "r_editlights : enable/disable editing mode\n"
4012 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4013 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4014 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4015 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4016 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4017 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4018 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4020 "r_editlights_help : this help\n"
4021 "r_editlights_clear : remove all lights\n"
4022 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4023 "r_editlights_save : save to .rtlights file\n"
4024 "r_editlights_spawn : create a light with default settings\n"
4025 "r_editlights_edit command : edit selected light - more documentation below\n"
4026 "r_editlights_remove : remove selected light\n"
4027 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4028 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4029 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4031 "origin x y z : set light location\n"
4032 "originx x: set x component of light location\n"
4033 "originy y: set y component of light location\n"
4034 "originz z: set z component of light location\n"
4035 "move x y z : adjust light location\n"
4036 "movex x: adjust x component of light location\n"
4037 "movey y: adjust y component of light location\n"
4038 "movez z: adjust z component of light location\n"
4039 "angles x y z : set light angles\n"
4040 "anglesx x: set x component of light angles\n"
4041 "anglesy y: set y component of light angles\n"
4042 "anglesz z: set z component of light angles\n"
4043 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4044 "radius radius : set radius (size) of light\n"
4045 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4046 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4047 "shadows 1/0 : turn on/off shadows\n"
4048 "corona n : set corona intensity\n"
4049 "coronasize n : set corona size (0-1)\n"
4050 "ambient n : set ambient intensity (0-1)\n"
4051 "diffuse n : set diffuse intensity (0-1)\n"
4052 "specular n : set specular intensity (0-1)\n"
4053 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4054 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4055 "<nothing> : print light properties to console\n"
4059 void R_Shadow_EditLights_CopyInfo_f(void)
4061 if (!r_editlights.integer)
4063 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4066 if (!r_shadow_selectedlight)
4068 Con_Print("No selected light.\n");
4071 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4072 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4073 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4074 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4075 if (r_shadow_selectedlight->cubemapname)
4076 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4078 r_shadow_bufferlight.cubemapname[0] = 0;
4079 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4080 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4081 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4082 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4083 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4084 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4085 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4088 void R_Shadow_EditLights_PasteInfo_f(void)
4090 if (!r_editlights.integer)
4092 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4095 if (!r_shadow_selectedlight)
4097 Con_Print("No selected light.\n");
4100 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);
4103 void R_Shadow_EditLights_Init(void)
4105 Cvar_RegisterVariable(&r_editlights);
4106 Cvar_RegisterVariable(&r_editlights_cursordistance);
4107 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4108 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4109 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4110 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4111 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4112 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4113 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4114 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4115 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4116 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4117 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4118 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4119 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4120 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4121 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4122 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4123 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4124 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4125 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4126 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);