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_blankwhitecubetexture;
159 // lights are reloaded when this changes
160 char r_shadow_mapname[MAX_QPATH];
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
165 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
166 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
167 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
168 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
169 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
170 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
171 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
172 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
173 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
174 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
175 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
176 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
177 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
178 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
179 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
180 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
181 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
182 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
183 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
184 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
185 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
186 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
187 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
188 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
189 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
190 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
191 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
192 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
193 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
194 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
195 cvar_t r_editlights = {0, "r_editlights", "0"};
196 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
197 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
198 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
199 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
200 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
201 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
202 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
204 float r_shadow_attenpower, r_shadow_attenscale;
206 rtlight_t *r_shadow_compilingrtlight;
207 dlight_t *r_shadow_worldlightchain;
208 dlight_t *r_shadow_selectedlight;
209 dlight_t r_shadow_bufferlight;
210 vec3_t r_editlights_cursorlocation;
212 rtexture_t *lighttextures[5];
214 extern int con_vislines;
216 typedef struct cubemapinfo_s
223 #define MAX_CUBEMAPS 256
224 static int numcubemaps;
225 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
227 #define SHADERPERMUTATION_SPECULAR (1<<0)
228 #define SHADERPERMUTATION_FOG (1<<1)
229 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
230 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
231 #define SHADERPERMUTATION_COUNT (1<<4)
233 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
235 void R_Shadow_UncompileWorldLights(void);
236 void R_Shadow_ClearWorldLights(void);
237 void R_Shadow_SaveWorldLights(void);
238 void R_Shadow_LoadWorldLights(void);
239 void R_Shadow_LoadLightsFile(void);
240 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
241 void R_Shadow_EditLights_Reload_f(void);
242 void R_Shadow_ValidateCvars(void);
243 static void R_Shadow_MakeTextures(void);
244 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
246 const char *builtinshader_light_vert =
247 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
248 "// written by Forest 'LordHavoc' Hale\n"
250 "uniform vec3 LightPosition;\n"
252 "varying vec2 TexCoord;\n"
253 "varying vec3 CubeVector;\n"
254 "varying vec3 LightVector;\n"
256 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
257 "uniform vec3 EyePosition;\n"
258 "varying vec3 EyeVector;\n"
261 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
265 " // copy the surface texcoord\n"
266 " TexCoord = gl_MultiTexCoord0.st;\n"
268 " // transform vertex position into light attenuation/cubemap space\n"
269 " // (-1 to +1 across the light box)\n"
270 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
272 " // transform unnormalized light direction into tangent space\n"
273 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
274 " // normalize it per pixel)\n"
275 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
276 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
277 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
278 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
280 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
281 " // transform unnormalized eye direction into tangent space\n"
282 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
283 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
284 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
285 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
288 " // transform vertex to camera space, using ftransform to match non-VS\n"
290 " gl_Position = ftransform();\n"
294 const char *builtinshader_light_frag =
295 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
296 "// written by Forest 'LordHavoc' Hale\n"
298 "uniform vec3 LightColor;\n"
300 "#ifdef USEOFFSETMAPPING\n"
301 "uniform float OffsetMapping_Scale;\n"
302 "uniform float OffsetMapping_Bias;\n"
304 "#ifdef USESPECULAR\n"
305 "uniform float SpecularPower;\n"
308 "uniform float FogRangeRecip;\n"
310 "uniform float AmbientScale;\n"
311 "uniform float DiffuseScale;\n"
312 "#ifdef USESPECULAR\n"
313 "uniform float SpecularScale;\n"
316 "uniform sampler2D Texture_Normal;\n"
317 "uniform sampler2D Texture_Color;\n"
318 "#ifdef USESPECULAR\n"
319 "uniform sampler2D Texture_Gloss;\n"
321 "#ifdef USECUBEFILTER\n"
322 "uniform samplerCube Texture_Cube;\n"
325 "uniform sampler2D Texture_FogMask;\n"
328 "varying vec2 TexCoord;\n"
329 "varying vec3 CubeVector;\n"
330 "varying vec3 LightVector;\n"
331 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
332 "varying vec3 EyeVector;\n"
339 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
340 " // center and sharp falloff at the edge, this is about the most efficient\n"
341 " // we can get away with as far as providing illumination.\n"
343 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
344 " // provide significant illumination, large = slow = pain.\n"
345 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
349 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
352 "#ifdef USEOFFSETMAPPING\n"
353 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
354 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
355 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
356 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
357 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
358 "#define TexCoord TexCoordOffset\n"
361 " // get the texels - with a blendmap we'd need to blend multiple here\n"
362 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
363 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
364 "#ifdef USESPECULAR\n"
365 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
368 " // calculate shading\n"
369 " vec3 diffusenormal = normalize(LightVector);\n"
370 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
371 "#ifdef USESPECULAR\n"
372 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
375 "#ifdef USECUBEFILTER\n"
376 " // apply light cubemap filter\n"
377 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
380 " // calculate fragment color\n"
381 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
385 void r_shadow_start(void)
388 // allocate vertex processing arrays
390 r_shadow_normalcubetexture = NULL;
391 r_shadow_attenuation2dtexture = NULL;
392 r_shadow_attenuation3dtexture = NULL;
393 r_shadow_blankwhitecubetexture = NULL;
394 r_shadow_texturepool = NULL;
395 r_shadow_filters_texturepool = NULL;
396 R_Shadow_ValidateCvars();
397 R_Shadow_MakeTextures();
398 maxshadowelements = 0;
399 shadowelements = NULL;
407 shadowmarklist = NULL;
409 r_shadow_buffer_numclusterpvsbytes = 0;
410 r_shadow_buffer_clusterpvs = NULL;
411 r_shadow_buffer_clusterlist = NULL;
412 r_shadow_buffer_numsurfacepvsbytes = 0;
413 r_shadow_buffer_surfacepvs = NULL;
414 r_shadow_buffer_surfacelist = NULL;
415 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
416 r_shadow_program_light[i] = 0;
417 if (gl_support_fragment_shader)
419 char *vertstring, *fragstring;
420 int vertstrings_count;
421 int fragstrings_count;
422 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
423 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
424 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
425 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
426 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
428 vertstrings_count = 0;
429 fragstrings_count = 0;
430 if (i & SHADERPERMUTATION_SPECULAR)
432 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
433 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
435 if (i & SHADERPERMUTATION_FOG)
437 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
438 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
440 if (i & SHADERPERMUTATION_CUBEFILTER)
442 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
443 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
445 if (i & SHADERPERMUTATION_OFFSETMAPPING)
447 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
448 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
450 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
451 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
452 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
453 if (!r_shadow_program_light[i])
455 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
458 qglUseProgramObjectARB(r_shadow_program_light[i]);
459 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
460 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
461 if (i & SHADERPERMUTATION_SPECULAR)
463 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
465 if (i & SHADERPERMUTATION_CUBEFILTER)
467 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
469 if (i & SHADERPERMUTATION_FOG)
471 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
474 qglUseProgramObjectARB(0);
476 Mem_Free(fragstring);
478 Mem_Free(vertstring);
482 void r_shadow_shutdown(void)
485 R_Shadow_UncompileWorldLights();
486 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
488 if (r_shadow_program_light[i])
490 GL_Backend_FreeProgram(r_shadow_program_light[i]);
491 r_shadow_program_light[i] = 0;
495 r_shadow_normalcubetexture = NULL;
496 r_shadow_attenuation2dtexture = NULL;
497 r_shadow_attenuation3dtexture = NULL;
498 r_shadow_blankwhitecubetexture = NULL;
499 R_FreeTexturePool(&r_shadow_texturepool);
500 R_FreeTexturePool(&r_shadow_filters_texturepool);
501 maxshadowelements = 0;
503 Mem_Free(shadowelements);
504 shadowelements = NULL;
507 Mem_Free(vertexupdate);
510 Mem_Free(vertexremap);
516 Mem_Free(shadowmark);
519 Mem_Free(shadowmarklist);
520 shadowmarklist = NULL;
522 r_shadow_buffer_numclusterpvsbytes = 0;
523 if (r_shadow_buffer_clusterpvs)
524 Mem_Free(r_shadow_buffer_clusterpvs);
525 r_shadow_buffer_clusterpvs = NULL;
526 if (r_shadow_buffer_clusterlist)
527 Mem_Free(r_shadow_buffer_clusterlist);
528 r_shadow_buffer_clusterlist = NULL;
529 r_shadow_buffer_numsurfacepvsbytes = 0;
530 if (r_shadow_buffer_surfacepvs)
531 Mem_Free(r_shadow_buffer_surfacepvs);
532 r_shadow_buffer_surfacepvs = NULL;
533 if (r_shadow_buffer_surfacelist)
534 Mem_Free(r_shadow_buffer_surfacelist);
535 r_shadow_buffer_surfacelist = NULL;
538 void r_shadow_newmap(void)
542 void R_Shadow_Help_f(void)
545 "Documentation on r_shadow system:\n"
547 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
548 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
549 "r_shadow_debuglight : render only this light number (-1 = all)\n"
550 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
551 "r_shadow_gloss2intensity : brightness of forced gloss\n"
552 "r_shadow_glossintensity : brightness of textured gloss\n"
553 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
554 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
555 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
556 "r_shadow_portallight : use portal visibility for static light precomputation\n"
557 "r_shadow_projectdistance : shadow volume projection distance\n"
558 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
559 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
560 "r_shadow_realtime_world : use high quality world lighting mode\n"
561 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
562 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
563 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
564 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
565 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
566 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
567 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
568 "r_shadow_scissor : use scissor optimization\n"
569 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
570 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
571 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
572 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
573 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
575 "r_shadow_help : this help\n"
579 void R_Shadow_Init(void)
581 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
582 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
583 Cvar_RegisterVariable(&r_shadow_cull);
584 Cvar_RegisterVariable(&r_shadow_debuglight);
585 Cvar_RegisterVariable(&r_shadow_gloss);
586 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
587 Cvar_RegisterVariable(&r_shadow_glossintensity);
588 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
589 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
590 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
591 Cvar_RegisterVariable(&r_shadow_portallight);
592 Cvar_RegisterVariable(&r_shadow_projectdistance);
593 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
594 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
595 Cvar_RegisterVariable(&r_shadow_realtime_world);
596 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
597 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
598 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
599 Cvar_RegisterVariable(&r_shadow_scissor);
600 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
601 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
602 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
603 Cvar_RegisterVariable(&r_shadow_staticworldlights);
604 Cvar_RegisterVariable(&r_shadow_texture3d);
605 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
606 Cvar_RegisterVariable(&r_shadow_glsl);
607 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
608 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
609 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
610 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
611 if (gamemode == GAME_TENEBRAE)
613 Cvar_SetValue("r_shadow_gloss", 2);
614 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
616 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
617 R_Shadow_EditLights_Init();
618 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
619 r_shadow_worldlightchain = NULL;
620 maxshadowelements = 0;
621 shadowelements = NULL;
629 shadowmarklist = NULL;
631 r_shadow_buffer_numclusterpvsbytes = 0;
632 r_shadow_buffer_clusterpvs = NULL;
633 r_shadow_buffer_clusterlist = NULL;
634 r_shadow_buffer_numsurfacepvsbytes = 0;
635 r_shadow_buffer_surfacepvs = NULL;
636 r_shadow_buffer_surfacelist = NULL;
637 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
640 matrix4x4_t matrix_attenuationxyz =
643 {0.5, 0.0, 0.0, 0.5},
644 {0.0, 0.5, 0.0, 0.5},
645 {0.0, 0.0, 0.5, 0.5},
650 matrix4x4_t matrix_attenuationz =
653 {0.0, 0.0, 0.5, 0.5},
654 {0.0, 0.0, 0.0, 0.5},
655 {0.0, 0.0, 0.0, 0.5},
660 int *R_Shadow_ResizeShadowElements(int numtris)
662 // make sure shadowelements is big enough for this volume
663 if (maxshadowelements < numtris * 24)
665 maxshadowelements = numtris * 24;
667 Mem_Free(shadowelements);
668 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
670 return shadowelements;
673 void R_Shadow_EnlargeClusterBuffer(int numclusters)
675 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
676 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
678 if (r_shadow_buffer_clusterpvs)
679 Mem_Free(r_shadow_buffer_clusterpvs);
680 if (r_shadow_buffer_clusterlist)
681 Mem_Free(r_shadow_buffer_clusterlist);
682 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
683 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
684 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
688 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
690 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
691 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
693 if (r_shadow_buffer_surfacepvs)
694 Mem_Free(r_shadow_buffer_surfacepvs);
695 if (r_shadow_buffer_surfacelist)
696 Mem_Free(r_shadow_buffer_surfacelist);
697 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
698 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
699 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
703 void R_Shadow_PrepareShadowMark(int numtris)
705 // make sure shadowmark is big enough for this volume
706 if (maxshadowmark < numtris)
708 maxshadowmark = numtris;
710 Mem_Free(shadowmark);
712 Mem_Free(shadowmarklist);
713 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
714 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
718 // if shadowmarkcount wrapped we clear the array and adjust accordingly
719 if (shadowmarkcount == 0)
722 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
727 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)
730 int outtriangles = 0, outvertices = 0;
734 if (maxvertexupdate < innumvertices)
736 maxvertexupdate = innumvertices;
738 Mem_Free(vertexupdate);
740 Mem_Free(vertexremap);
741 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
742 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
746 if (vertexupdatenum == 0)
749 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
750 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
753 for (i = 0;i < numshadowmarktris;i++)
754 shadowmark[shadowmarktris[i]] = shadowmarkcount;
756 for (i = 0;i < numshadowmarktris;i++)
758 element = inelement3i + shadowmarktris[i] * 3;
759 // make sure the vertices are created
760 for (j = 0;j < 3;j++)
762 if (vertexupdate[element[j]] != vertexupdatenum)
764 float ratio, direction[3];
765 vertexupdate[element[j]] = vertexupdatenum;
766 vertexremap[element[j]] = outvertices;
767 vertex = invertex3f + element[j] * 3;
768 // project one copy of the vertex to the sphere radius of the light
769 // (FIXME: would projecting it to the light box be better?)
770 VectorSubtract(vertex, projectorigin, direction);
771 ratio = projectdistance / VectorLength(direction);
772 VectorCopy(vertex, outvertex3f);
773 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
780 for (i = 0;i < numshadowmarktris;i++)
782 int remappedelement[3];
784 const int *neighbortriangle;
786 markindex = shadowmarktris[i] * 3;
787 element = inelement3i + markindex;
788 neighbortriangle = inneighbor3i + markindex;
789 // output the front and back triangles
790 outelement3i[0] = vertexremap[element[0]];
791 outelement3i[1] = vertexremap[element[1]];
792 outelement3i[2] = vertexremap[element[2]];
793 outelement3i[3] = vertexremap[element[2]] + 1;
794 outelement3i[4] = vertexremap[element[1]] + 1;
795 outelement3i[5] = vertexremap[element[0]] + 1;
799 // output the sides (facing outward from this triangle)
800 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
802 remappedelement[0] = vertexremap[element[0]];
803 remappedelement[1] = vertexremap[element[1]];
804 outelement3i[0] = remappedelement[1];
805 outelement3i[1] = remappedelement[0];
806 outelement3i[2] = remappedelement[0] + 1;
807 outelement3i[3] = remappedelement[1];
808 outelement3i[4] = remappedelement[0] + 1;
809 outelement3i[5] = remappedelement[1] + 1;
814 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
816 remappedelement[1] = vertexremap[element[1]];
817 remappedelement[2] = vertexremap[element[2]];
818 outelement3i[0] = remappedelement[2];
819 outelement3i[1] = remappedelement[1];
820 outelement3i[2] = remappedelement[1] + 1;
821 outelement3i[3] = remappedelement[2];
822 outelement3i[4] = remappedelement[1] + 1;
823 outelement3i[5] = remappedelement[2] + 1;
828 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
830 remappedelement[0] = vertexremap[element[0]];
831 remappedelement[2] = vertexremap[element[2]];
832 outelement3i[0] = remappedelement[0];
833 outelement3i[1] = remappedelement[2];
834 outelement3i[2] = remappedelement[2] + 1;
835 outelement3i[3] = remappedelement[0];
836 outelement3i[4] = remappedelement[2] + 1;
837 outelement3i[5] = remappedelement[0] + 1;
844 *outnumvertices = outvertices;
848 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)
851 if (projectdistance < 0.1)
853 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
856 if (!numverts || !nummarktris)
858 // make sure shadowelements is big enough for this volume
859 if (maxshadowelements < nummarktris * 24)
860 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
861 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
862 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
865 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
870 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
872 tend = firsttriangle + numtris;
873 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
874 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
875 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
877 // surface box entirely inside light box, no box cull
878 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
879 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
880 shadowmarklist[numshadowmark++] = t;
884 // surface box not entirely inside light box, cull each triangle
885 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
887 v[0] = invertex3f + e[0] * 3;
888 v[1] = invertex3f + e[1] * 3;
889 v[2] = invertex3f + e[2] * 3;
890 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
891 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
892 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
893 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
894 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
895 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
896 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
897 shadowmarklist[numshadowmark++] = t;
902 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
905 if (r_shadow_compilingrtlight)
907 // if we're compiling an rtlight, capture the mesh
908 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
911 memset(&m, 0, sizeof(m));
912 m.pointer_vertex = vertex3f;
914 GL_LockArrays(0, numvertices);
915 if (r_shadowstage == SHADOWSTAGE_STENCIL)
917 // increment stencil if backface is behind depthbuffer
918 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
919 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
920 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
922 c_rt_shadowtris += numtriangles;
923 // decrement stencil if frontface is behind depthbuffer
924 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
925 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
927 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
929 c_rt_shadowtris += numtriangles;
933 static void R_Shadow_MakeTextures(void)
935 int x, y, z, d, side;
936 float v[3], s, t, intensity;
938 R_FreeTexturePool(&r_shadow_texturepool);
939 r_shadow_texturepool = R_AllocTexturePool();
940 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
941 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
943 #define ATTEN2DSIZE 64
944 #define ATTEN3DSIZE 32
945 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
946 r_shadow_blankwhitecubetexture = NULL;
947 r_shadow_normalcubetexture = NULL;
948 if (gl_texturecubemap)
950 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
951 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
952 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
953 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
954 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
955 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
956 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
957 for (side = 0;side < 6;side++)
959 for (y = 0;y < NORMSIZE;y++)
961 for (x = 0;x < NORMSIZE;x++)
963 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
964 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
998 intensity = 127.0f / sqrt(DotProduct(v, v));
999 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1000 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1001 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1002 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1006 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1008 for (y = 0;y < ATTEN2DSIZE;y++)
1010 for (x = 0;x < ATTEN2DSIZE;x++)
1012 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1013 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1015 intensity = 1.0f - sqrt(DotProduct(v, v));
1017 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1018 d = bound(0, intensity, 255);
1019 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1020 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1021 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1022 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1025 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1026 if (r_shadow_texture3d.integer)
1028 for (z = 0;z < ATTEN3DSIZE;z++)
1030 for (y = 0;y < ATTEN3DSIZE;y++)
1032 for (x = 0;x < ATTEN3DSIZE;x++)
1034 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1035 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1036 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1037 intensity = 1.0f - sqrt(DotProduct(v, v));
1039 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1040 d = bound(0, intensity, 255);
1041 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1042 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1043 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1044 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1048 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1053 void R_Shadow_ValidateCvars(void)
1055 if (r_shadow_texture3d.integer && !gl_texture3d)
1056 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1057 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1058 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1061 void R_Shadow_Stage_Begin(void)
1065 R_Shadow_ValidateCvars();
1067 if (!r_shadow_attenuation2dtexture
1068 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1069 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1070 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1071 R_Shadow_MakeTextures();
1073 memset(&m, 0, sizeof(m));
1074 GL_BlendFunc(GL_ONE, GL_ZERO);
1075 GL_DepthMask(false);
1078 GL_Color(0, 0, 0, 1);
1079 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1080 qglEnable(GL_CULL_FACE);
1081 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1082 r_shadowstage = SHADOWSTAGE_NONE;
1085 void R_Shadow_Stage_ShadowVolumes(void)
1088 memset(&m, 0, sizeof(m));
1090 GL_Color(1, 1, 1, 1);
1091 GL_ColorMask(0, 0, 0, 0);
1092 GL_BlendFunc(GL_ONE, GL_ZERO);
1093 GL_DepthMask(false);
1095 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1096 //if (r_shadow_shadow_polygonoffset.value != 0)
1098 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1099 // qglEnable(GL_POLYGON_OFFSET_FILL);
1102 // qglDisable(GL_POLYGON_OFFSET_FILL);
1103 qglDepthFunc(GL_LESS);
1104 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1105 qglEnable(GL_STENCIL_TEST);
1106 qglStencilFunc(GL_ALWAYS, 128, ~0);
1107 if (gl_ext_stenciltwoside.integer)
1109 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1110 qglDisable(GL_CULL_FACE);
1111 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1112 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1114 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1115 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1117 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1121 r_shadowstage = SHADOWSTAGE_STENCIL;
1122 qglEnable(GL_CULL_FACE);
1124 // this is changed by every shadow render so its value here is unimportant
1125 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1127 GL_Clear(GL_STENCIL_BUFFER_BIT);
1129 // LordHavoc note: many shadow volumes reside entirely inside the world
1130 // (that is to say they are entirely bounded by their lit surfaces),
1131 // which can be optimized by handling things as an inverted light volume,
1132 // with the shadow boundaries of the world being simulated by an altered
1133 // (129) bias to stencil clearing on such lights
1134 // FIXME: generate inverted light volumes for use as shadow volumes and
1135 // optimize for them as noted above
1138 void R_Shadow_Stage_Light(int shadowtest)
1141 memset(&m, 0, sizeof(m));
1143 GL_BlendFunc(GL_ONE, GL_ONE);
1144 GL_DepthMask(false);
1146 qglPolygonOffset(0, 0);
1147 //qglDisable(GL_POLYGON_OFFSET_FILL);
1148 GL_Color(1, 1, 1, 1);
1149 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1150 qglDepthFunc(GL_EQUAL);
1151 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1152 qglEnable(GL_CULL_FACE);
1154 qglEnable(GL_STENCIL_TEST);
1156 qglDisable(GL_STENCIL_TEST);
1157 if (gl_support_stenciltwoside)
1158 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1160 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1161 // only draw light where this geometry was already rendered AND the
1162 // stencil is 128 (values other than this mean shadow)
1163 qglStencilFunc(GL_EQUAL, 128, ~0);
1164 r_shadowstage = SHADOWSTAGE_LIGHT;
1168 void R_Shadow_Stage_End(void)
1171 memset(&m, 0, sizeof(m));
1173 GL_BlendFunc(GL_ONE, GL_ZERO);
1176 qglPolygonOffset(0, 0);
1177 //qglDisable(GL_POLYGON_OFFSET_FILL);
1178 GL_Color(1, 1, 1, 1);
1179 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1180 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1181 qglDepthFunc(GL_LEQUAL);
1182 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1183 qglDisable(GL_STENCIL_TEST);
1184 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1185 if (gl_support_stenciltwoside)
1186 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1188 qglStencilFunc(GL_ALWAYS, 128, ~0);
1189 r_shadowstage = SHADOWSTAGE_NONE;
1192 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1194 int i, ix1, iy1, ix2, iy2;
1195 float x1, y1, x2, y2, x, y, f;
1196 vec3_t smins, smaxs;
1198 if (!r_shadow_scissor.integer)
1200 // if view is inside the box, just say yes it's visible
1201 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1203 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1206 for (i = 0;i < 3;i++)
1208 if (r_viewforward[i] >= 0)
1219 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1220 if (DotProduct(r_viewforward, v2) <= f)
1222 // entirely behind nearclip plane
1225 if (DotProduct(r_viewforward, v) >= f)
1227 // entirely infront of nearclip plane
1228 x1 = y1 = x2 = y2 = 0;
1229 for (i = 0;i < 8;i++)
1231 v[0] = (i & 1) ? mins[0] : maxs[0];
1232 v[1] = (i & 2) ? mins[1] : maxs[1];
1233 v[2] = (i & 4) ? mins[2] : maxs[2];
1235 GL_TransformToScreen(v, v2);
1236 //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]);
1255 // clipped by nearclip plane
1256 // this is nasty and crude...
1257 // create viewspace bbox
1258 for (i = 0;i < 8;i++)
1260 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1261 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1262 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1263 v2[0] = -DotProduct(v, r_viewleft);
1264 v2[1] = DotProduct(v, r_viewup);
1265 v2[2] = DotProduct(v, r_viewforward);
1268 if (smins[0] > v2[0]) smins[0] = v2[0];
1269 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1270 if (smins[1] > v2[1]) smins[1] = v2[1];
1271 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1272 if (smins[2] > v2[2]) smins[2] = v2[2];
1273 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1277 smins[0] = smaxs[0] = v2[0];
1278 smins[1] = smaxs[1] = v2[1];
1279 smins[2] = smaxs[2] = v2[2];
1282 // now we have a bbox in viewspace
1283 // clip it to the view plane
1286 // return true if that culled the box
1287 if (smins[2] >= smaxs[2])
1289 // ok some of it is infront of the view, transform each corner back to
1290 // worldspace and then to screenspace and make screen rect
1291 // initialize these variables just to avoid compiler warnings
1292 x1 = y1 = x2 = y2 = 0;
1293 for (i = 0;i < 8;i++)
1295 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1296 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1297 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1298 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1299 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1300 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1302 GL_TransformToScreen(v, v2);
1303 //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]);
1320 // this code doesn't handle boxes with any points behind view properly
1321 x1 = 1000;x2 = -1000;
1322 y1 = 1000;y2 = -1000;
1323 for (i = 0;i < 8;i++)
1325 v[0] = (i & 1) ? mins[0] : maxs[0];
1326 v[1] = (i & 2) ? mins[1] : maxs[1];
1327 v[2] = (i & 4) ? mins[2] : maxs[2];
1329 GL_TransformToScreen(v, v2);
1330 //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]);
1348 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1349 if (ix1 < r_view_x) ix1 = r_view_x;
1350 if (iy1 < r_view_y) iy1 = r_view_y;
1351 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1352 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1353 if (ix2 <= ix1 || iy2 <= iy1)
1355 // set up the scissor rectangle
1356 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1357 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1358 //qglEnable(GL_SCISSOR_TEST);
1363 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1365 float *color4f = varray_color4f;
1366 float dist, dot, intensity, v[3], n[3];
1367 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1369 Matrix4x4_Transform(m, vertex3f, v);
1370 if ((dist = DotProduct(v, v)) < 1)
1372 Matrix4x4_Transform3x3(m, normal3f, n);
1373 if ((dot = DotProduct(n, v)) > 0)
1376 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1377 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1378 VectorScale(lightcolor, intensity, color4f);
1383 VectorClear(color4f);
1389 VectorClear(color4f);
1395 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1397 float *color4f = varray_color4f;
1398 float dist, dot, intensity, v[3], n[3];
1399 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1401 Matrix4x4_Transform(m, vertex3f, v);
1402 if ((dist = fabs(v[2])) < 1)
1404 Matrix4x4_Transform3x3(m, normal3f, n);
1405 if ((dot = DotProduct(n, v)) > 0)
1407 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1408 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1409 VectorScale(lightcolor, intensity, color4f);
1414 VectorClear(color4f);
1420 VectorClear(color4f);
1426 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1428 float *color4f = varray_color4f;
1429 float dot, intensity, v[3], n[3];
1430 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1432 Matrix4x4_Transform(m, vertex3f, v);
1433 Matrix4x4_Transform3x3(m, normal3f, n);
1434 if ((dot = DotProduct(n, v)) > 0)
1436 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1437 VectorScale(lightcolor, intensity, color4f);
1442 VectorClear(color4f);
1448 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1450 float *color4f = varray_color4f;
1451 float dist, intensity, v[3];
1452 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1454 Matrix4x4_Transform(m, vertex3f, v);
1455 if ((dist = DotProduct(v, v)) < 1)
1458 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1459 VectorScale(lightcolor, intensity, color4f);
1464 VectorClear(color4f);
1470 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1472 float *color4f = varray_color4f;
1473 float dist, intensity, v[3];
1474 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1476 Matrix4x4_Transform(m, vertex3f, v);
1477 if ((dist = fabs(v[2])) < 1)
1479 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1480 VectorScale(lightcolor, intensity, color4f);
1485 VectorClear(color4f);
1491 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1492 #define USETEXMATRIX
1494 #ifndef USETEXMATRIX
1495 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1496 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1497 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1501 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1502 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1503 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1510 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1514 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1515 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1523 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)
1527 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1529 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1530 // the cubemap normalizes this for us
1531 out3f[0] = DotProduct(svector3f, lightdir);
1532 out3f[1] = DotProduct(tvector3f, lightdir);
1533 out3f[2] = DotProduct(normal3f, lightdir);
1537 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)
1540 float lightdir[3], eyedir[3], halfdir[3];
1541 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1543 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1544 VectorNormalizeFast(lightdir);
1545 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1546 VectorNormalizeFast(eyedir);
1547 VectorAdd(lightdir, eyedir, halfdir);
1548 // the cubemap normalizes this for us
1549 out3f[0] = DotProduct(svector3f, halfdir);
1550 out3f[1] = DotProduct(tvector3f, halfdir);
1551 out3f[2] = DotProduct(normal3f, halfdir);
1555 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)
1558 float color[3], color2[3], colorscale;
1560 // FIXME: support EF_NODEPTHTEST
1561 GL_DepthMask(false);
1564 bumptexture = r_texture_blanknormalmap;
1565 specularscale *= r_shadow_glossintensity.value;
1568 if (r_shadow_gloss.integer >= 2)
1570 glosstexture = r_texture_white;
1571 specularscale *= r_shadow_gloss2intensity.value;
1575 glosstexture = r_texture_black;
1579 if (r_shadow_gloss.integer < 1)
1582 lightcubemap = r_shadow_blankwhitecubetexture;
1583 if (ambientscale + diffusescale + specularscale < 0.01)
1585 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1587 unsigned int perm, prog;
1588 // GLSL shader path (GFFX5200, Radeon 9500)
1589 memset(&m, 0, sizeof(m));
1590 m.pointer_vertex = vertex3f;
1591 m.pointer_texcoord[0] = texcoord2f;
1592 m.pointer_texcoord3f[1] = svector3f;
1593 m.pointer_texcoord3f[2] = tvector3f;
1594 m.pointer_texcoord3f[3] = normal3f;
1595 m.tex[0] = R_GetTexture(bumptexture);
1596 m.tex[1] = R_GetTexture(basetexture);
1597 m.tex[2] = R_GetTexture(glosstexture);
1598 m.texcubemap[3] = R_GetTexture(lightcubemap);
1599 // TODO: support fog (after renderer is converted to texture fog)
1600 m.tex[4] = R_GetTexture(r_texture_white);
1601 m.texmatrix[3] = *matrix_modeltolight;
1603 GL_BlendFunc(GL_ONE, GL_ONE);
1604 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1607 // only add a feature to the permutation if that permutation exists
1608 // (otherwise it might end up not using a shader at all, which looks
1609 // worse than using less features)
1610 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1611 perm |= SHADERPERMUTATION_SPECULAR;
1612 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1613 // perm |= SHADERPERMUTATION_FOG;
1614 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1615 perm |= SHADERPERMUTATION_CUBEFILTER;
1616 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1617 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1618 prog = r_shadow_program_light[perm];
1619 qglUseProgramObjectARB(prog);CHECKGLERROR
1620 // TODO: support fog (after renderer is converted to texture fog)
1621 if (perm & SHADERPERMUTATION_FOG)
1623 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1625 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1626 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1627 if (perm & SHADERPERMUTATION_SPECULAR)
1629 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1630 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1632 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);CHECKGLERROR
1633 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1634 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1636 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1638 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1640 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1641 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1644 GL_LockArrays(0, numverts);
1645 R_Mesh_Draw(0, numverts, numtriangles, elements);
1647 c_rt_lighttris += numtriangles;
1648 GL_LockArrays(0, 0);
1649 qglUseProgramObjectARB(0);
1650 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1651 qglBegin(GL_TRIANGLES);
1655 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1658 bumptexture = r_texture_blanknormalmap;
1660 glosstexture = r_texture_white;
1664 colorscale = ambientscale;
1665 // colorscale accounts for how much we multiply the brightness
1668 // mult is how many times the final pass of the lighting will be
1669 // performed to get more brightness than otherwise possible.
1671 // Limit mult to 64 for sanity sake.
1672 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1674 // 3 3D combine path (Geforce3, Radeon 8500)
1675 memset(&m, 0, sizeof(m));
1676 m.pointer_vertex = vertex3f;
1677 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1679 m.pointer_texcoord3f[0] = vertex3f;
1680 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1682 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1683 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1685 m.tex[1] = R_GetTexture(basetexture);
1686 m.pointer_texcoord[1] = texcoord2f;
1687 m.texcubemap[2] = R_GetTexture(lightcubemap);
1689 m.pointer_texcoord3f[2] = vertex3f;
1690 m.texmatrix[2] = *matrix_modeltolight;
1692 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1693 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1695 GL_BlendFunc(GL_ONE, GL_ONE);
1697 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1699 // 2 3D combine path (Geforce3, original Radeon)
1700 memset(&m, 0, sizeof(m));
1701 m.pointer_vertex = vertex3f;
1702 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1704 m.pointer_texcoord3f[0] = vertex3f;
1705 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1707 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1708 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1710 m.tex[1] = R_GetTexture(basetexture);
1711 m.pointer_texcoord[1] = texcoord2f;
1712 GL_BlendFunc(GL_ONE, GL_ONE);
1714 else if (r_textureunits.integer >= 4 && lightcubemap)
1716 // 4 2D combine path (Geforce3, Radeon 8500)
1717 memset(&m, 0, sizeof(m));
1718 m.pointer_vertex = vertex3f;
1719 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1721 m.pointer_texcoord3f[0] = vertex3f;
1722 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1724 m.pointer_texcoord[0] = varray_texcoord2f[0];
1725 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1727 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1729 m.pointer_texcoord3f[1] = vertex3f;
1730 m.texmatrix[1] = *matrix_modeltoattenuationz;
1732 m.pointer_texcoord[1] = varray_texcoord2f[1];
1733 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1735 m.tex[2] = R_GetTexture(basetexture);
1736 m.pointer_texcoord[2] = texcoord2f;
1739 m.texcubemap[3] = R_GetTexture(lightcubemap);
1741 m.pointer_texcoord3f[3] = vertex3f;
1742 m.texmatrix[3] = *matrix_modeltolight;
1744 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1745 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1748 GL_BlendFunc(GL_ONE, GL_ONE);
1750 else if (r_textureunits.integer >= 3 && !lightcubemap)
1752 // 3 2D combine path (Geforce3, original Radeon)
1753 memset(&m, 0, sizeof(m));
1754 m.pointer_vertex = vertex3f;
1755 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1757 m.pointer_texcoord3f[0] = vertex3f;
1758 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1760 m.pointer_texcoord[0] = varray_texcoord2f[0];
1761 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1763 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1765 m.pointer_texcoord3f[1] = vertex3f;
1766 m.texmatrix[1] = *matrix_modeltoattenuationz;
1768 m.pointer_texcoord[1] = varray_texcoord2f[1];
1769 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1771 m.tex[2] = R_GetTexture(basetexture);
1772 m.pointer_texcoord[2] = texcoord2f;
1773 GL_BlendFunc(GL_ONE, GL_ONE);
1777 // 2/2/2 2D combine path (any dot3 card)
1778 memset(&m, 0, sizeof(m));
1779 m.pointer_vertex = vertex3f;
1780 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1782 m.pointer_texcoord3f[0] = vertex3f;
1783 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1785 m.pointer_texcoord[0] = varray_texcoord2f[0];
1786 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1788 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1790 m.pointer_texcoord3f[1] = vertex3f;
1791 m.texmatrix[1] = *matrix_modeltoattenuationz;
1793 m.pointer_texcoord[1] = varray_texcoord2f[1];
1794 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1797 GL_ColorMask(0,0,0,1);
1798 GL_BlendFunc(GL_ONE, GL_ZERO);
1799 GL_LockArrays(0, numverts);
1800 R_Mesh_Draw(0, numverts, numtriangles, elements);
1801 GL_LockArrays(0, 0);
1803 c_rt_lighttris += numtriangles;
1805 memset(&m, 0, sizeof(m));
1806 m.pointer_vertex = vertex3f;
1807 m.tex[0] = R_GetTexture(basetexture);
1808 m.pointer_texcoord[0] = texcoord2f;
1811 m.texcubemap[1] = R_GetTexture(lightcubemap);
1813 m.pointer_texcoord3f[1] = vertex3f;
1814 m.texmatrix[1] = *matrix_modeltolight;
1816 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1817 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1820 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1822 // this final code is shared
1824 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1825 VectorScale(lightcolor, colorscale, color2);
1826 GL_LockArrays(0, numverts);
1827 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1829 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1830 R_Mesh_Draw(0, numverts, numtriangles, elements);
1832 c_rt_lighttris += numtriangles;
1834 GL_LockArrays(0, 0);
1839 colorscale = diffusescale;
1840 // colorscale accounts for how much we multiply the brightness
1843 // mult is how many times the final pass of the lighting will be
1844 // performed to get more brightness than otherwise possible.
1846 // Limit mult to 64 for sanity sake.
1847 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1849 // 3/2 3D combine path (Geforce3, Radeon 8500)
1850 memset(&m, 0, sizeof(m));
1851 m.pointer_vertex = vertex3f;
1852 m.tex[0] = R_GetTexture(bumptexture);
1853 m.texcombinergb[0] = GL_REPLACE;
1854 m.pointer_texcoord[0] = texcoord2f;
1855 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1856 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1857 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1858 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1859 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1861 m.pointer_texcoord3f[2] = vertex3f;
1862 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1864 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1865 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1868 GL_ColorMask(0,0,0,1);
1869 GL_BlendFunc(GL_ONE, GL_ZERO);
1870 GL_LockArrays(0, numverts);
1871 R_Mesh_Draw(0, numverts, numtriangles, elements);
1872 GL_LockArrays(0, 0);
1874 c_rt_lighttris += numtriangles;
1876 memset(&m, 0, sizeof(m));
1877 m.pointer_vertex = vertex3f;
1878 m.tex[0] = R_GetTexture(basetexture);
1879 m.pointer_texcoord[0] = texcoord2f;
1882 m.texcubemap[1] = R_GetTexture(lightcubemap);
1884 m.pointer_texcoord3f[1] = vertex3f;
1885 m.texmatrix[1] = *matrix_modeltolight;
1887 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1888 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1891 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1893 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1895 // 1/2/2 3D combine path (original Radeon)
1896 memset(&m, 0, sizeof(m));
1897 m.pointer_vertex = vertex3f;
1898 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1900 m.pointer_texcoord3f[0] = vertex3f;
1901 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1903 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1904 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1907 GL_ColorMask(0,0,0,1);
1908 GL_BlendFunc(GL_ONE, GL_ZERO);
1909 GL_LockArrays(0, numverts);
1910 R_Mesh_Draw(0, numverts, numtriangles, elements);
1911 GL_LockArrays(0, 0);
1913 c_rt_lighttris += numtriangles;
1915 memset(&m, 0, sizeof(m));
1916 m.pointer_vertex = vertex3f;
1917 m.tex[0] = R_GetTexture(bumptexture);
1918 m.texcombinergb[0] = GL_REPLACE;
1919 m.pointer_texcoord[0] = texcoord2f;
1920 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1921 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1922 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1923 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1925 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1926 GL_LockArrays(0, numverts);
1927 R_Mesh_Draw(0, numverts, numtriangles, elements);
1928 GL_LockArrays(0, 0);
1930 c_rt_lighttris += numtriangles;
1932 memset(&m, 0, sizeof(m));
1933 m.pointer_vertex = vertex3f;
1934 m.tex[0] = R_GetTexture(basetexture);
1935 m.pointer_texcoord[0] = texcoord2f;
1938 m.texcubemap[1] = R_GetTexture(lightcubemap);
1940 m.pointer_texcoord3f[1] = vertex3f;
1941 m.texmatrix[1] = *matrix_modeltolight;
1943 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1944 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1947 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1949 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1951 // 2/2 3D combine path (original Radeon)
1952 memset(&m, 0, sizeof(m));
1953 m.pointer_vertex = vertex3f;
1954 m.tex[0] = R_GetTexture(bumptexture);
1955 m.texcombinergb[0] = GL_REPLACE;
1956 m.pointer_texcoord[0] = texcoord2f;
1957 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1958 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1959 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1960 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1962 GL_ColorMask(0,0,0,1);
1963 GL_BlendFunc(GL_ONE, GL_ZERO);
1964 GL_LockArrays(0, numverts);
1965 R_Mesh_Draw(0, numverts, numtriangles, elements);
1966 GL_LockArrays(0, 0);
1968 c_rt_lighttris += numtriangles;
1970 memset(&m, 0, sizeof(m));
1971 m.pointer_vertex = vertex3f;
1972 m.tex[0] = R_GetTexture(basetexture);
1973 m.pointer_texcoord[0] = texcoord2f;
1974 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1976 m.pointer_texcoord3f[1] = vertex3f;
1977 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1979 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1980 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1982 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1984 else if (r_textureunits.integer >= 4)
1986 // 4/2 2D combine path (Geforce3, Radeon 8500)
1987 memset(&m, 0, sizeof(m));
1988 m.pointer_vertex = vertex3f;
1989 m.tex[0] = R_GetTexture(bumptexture);
1990 m.texcombinergb[0] = GL_REPLACE;
1991 m.pointer_texcoord[0] = texcoord2f;
1992 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1993 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1994 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1995 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1996 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1998 m.pointer_texcoord3f[2] = vertex3f;
1999 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2001 m.pointer_texcoord[2] = varray_texcoord2f[2];
2002 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2004 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2006 m.pointer_texcoord3f[3] = vertex3f;
2007 m.texmatrix[3] = *matrix_modeltoattenuationz;
2009 m.pointer_texcoord[3] = varray_texcoord2f[3];
2010 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2013 GL_ColorMask(0,0,0,1);
2014 GL_BlendFunc(GL_ONE, GL_ZERO);
2015 GL_LockArrays(0, numverts);
2016 R_Mesh_Draw(0, numverts, numtriangles, elements);
2017 GL_LockArrays(0, 0);
2019 c_rt_lighttris += numtriangles;
2021 memset(&m, 0, sizeof(m));
2022 m.pointer_vertex = vertex3f;
2023 m.tex[0] = R_GetTexture(basetexture);
2024 m.pointer_texcoord[0] = texcoord2f;
2027 m.texcubemap[1] = R_GetTexture(lightcubemap);
2029 m.pointer_texcoord3f[1] = vertex3f;
2030 m.texmatrix[1] = *matrix_modeltolight;
2032 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2033 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2036 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2040 // 2/2/2 2D combine path (any dot3 card)
2041 memset(&m, 0, sizeof(m));
2042 m.pointer_vertex = vertex3f;
2043 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2045 m.pointer_texcoord3f[0] = vertex3f;
2046 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2048 m.pointer_texcoord[0] = varray_texcoord2f[0];
2049 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2051 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2053 m.pointer_texcoord3f[1] = vertex3f;
2054 m.texmatrix[1] = *matrix_modeltoattenuationz;
2056 m.pointer_texcoord[1] = varray_texcoord2f[1];
2057 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2060 GL_ColorMask(0,0,0,1);
2061 GL_BlendFunc(GL_ONE, GL_ZERO);
2062 GL_LockArrays(0, numverts);
2063 R_Mesh_Draw(0, numverts, numtriangles, elements);
2064 GL_LockArrays(0, 0);
2066 c_rt_lighttris += numtriangles;
2068 memset(&m, 0, sizeof(m));
2069 m.pointer_vertex = vertex3f;
2070 m.tex[0] = R_GetTexture(bumptexture);
2071 m.texcombinergb[0] = GL_REPLACE;
2072 m.pointer_texcoord[0] = texcoord2f;
2073 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2074 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2075 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2076 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2078 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2079 GL_LockArrays(0, numverts);
2080 R_Mesh_Draw(0, numverts, numtriangles, elements);
2081 GL_LockArrays(0, 0);
2083 c_rt_lighttris += numtriangles;
2085 memset(&m, 0, sizeof(m));
2086 m.pointer_vertex = vertex3f;
2087 m.tex[0] = R_GetTexture(basetexture);
2088 m.pointer_texcoord[0] = texcoord2f;
2091 m.texcubemap[1] = R_GetTexture(lightcubemap);
2093 m.pointer_texcoord3f[1] = vertex3f;
2094 m.texmatrix[1] = *matrix_modeltolight;
2096 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2097 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2100 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2102 // this final code is shared
2104 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2105 VectorScale(lightcolor, colorscale, color2);
2106 GL_LockArrays(0, numverts);
2107 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2109 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2110 R_Mesh_Draw(0, numverts, numtriangles, elements);
2112 c_rt_lighttris += numtriangles;
2114 GL_LockArrays(0, 0);
2116 if (specularscale && glosstexture != r_texture_black)
2118 // FIXME: detect blendsquare!
2119 //if (gl_support_blendsquare)
2121 colorscale = specularscale;
2123 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2125 // 2/0/0/1/2 3D combine blendsquare path
2126 memset(&m, 0, sizeof(m));
2127 m.pointer_vertex = vertex3f;
2128 m.tex[0] = R_GetTexture(bumptexture);
2129 m.pointer_texcoord[0] = texcoord2f;
2130 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2131 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2132 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2133 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2135 GL_ColorMask(0,0,0,1);
2136 // this squares the result
2137 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2138 GL_LockArrays(0, numverts);
2139 R_Mesh_Draw(0, numverts, numtriangles, elements);
2140 GL_LockArrays(0, 0);
2142 c_rt_lighttris += numtriangles;
2144 memset(&m, 0, sizeof(m));
2145 m.pointer_vertex = vertex3f;
2147 GL_LockArrays(0, numverts);
2148 // square alpha in framebuffer a few times to make it shiny
2149 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2150 // these comments are a test run through this math for intensity 0.5
2151 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2152 // 0.25 * 0.25 = 0.0625 (this is another pass)
2153 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2154 R_Mesh_Draw(0, numverts, numtriangles, elements);
2156 c_rt_lighttris += numtriangles;
2157 R_Mesh_Draw(0, numverts, numtriangles, elements);
2159 c_rt_lighttris += numtriangles;
2160 GL_LockArrays(0, 0);
2162 memset(&m, 0, sizeof(m));
2163 m.pointer_vertex = vertex3f;
2164 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2166 m.pointer_texcoord3f[0] = vertex3f;
2167 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2169 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2170 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2173 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2174 GL_LockArrays(0, numverts);
2175 R_Mesh_Draw(0, numverts, numtriangles, elements);
2176 GL_LockArrays(0, 0);
2178 c_rt_lighttris += numtriangles;
2180 memset(&m, 0, sizeof(m));
2181 m.pointer_vertex = vertex3f;
2182 m.tex[0] = R_GetTexture(glosstexture);
2183 m.pointer_texcoord[0] = texcoord2f;
2186 m.texcubemap[1] = R_GetTexture(lightcubemap);
2188 m.pointer_texcoord3f[1] = vertex3f;
2189 m.texmatrix[1] = *matrix_modeltolight;
2191 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2192 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2195 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2197 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2199 // 2/0/0/2 3D combine blendsquare path
2200 memset(&m, 0, sizeof(m));
2201 m.pointer_vertex = vertex3f;
2202 m.tex[0] = R_GetTexture(bumptexture);
2203 m.pointer_texcoord[0] = texcoord2f;
2204 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2205 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2206 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2207 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2209 GL_ColorMask(0,0,0,1);
2210 // this squares the result
2211 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2212 GL_LockArrays(0, numverts);
2213 R_Mesh_Draw(0, numverts, numtriangles, elements);
2214 GL_LockArrays(0, 0);
2216 c_rt_lighttris += numtriangles;
2218 memset(&m, 0, sizeof(m));
2219 m.pointer_vertex = vertex3f;
2221 GL_LockArrays(0, numverts);
2222 // square alpha in framebuffer a few times to make it shiny
2223 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2224 // these comments are a test run through this math for intensity 0.5
2225 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2226 // 0.25 * 0.25 = 0.0625 (this is another pass)
2227 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2228 R_Mesh_Draw(0, numverts, numtriangles, elements);
2230 c_rt_lighttris += numtriangles;
2231 R_Mesh_Draw(0, numverts, numtriangles, elements);
2233 c_rt_lighttris += numtriangles;
2234 GL_LockArrays(0, 0);
2236 memset(&m, 0, sizeof(m));
2237 m.pointer_vertex = vertex3f;
2238 m.tex[0] = R_GetTexture(glosstexture);
2239 m.pointer_texcoord[0] = texcoord2f;
2240 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2242 m.pointer_texcoord3f[1] = vertex3f;
2243 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2245 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2246 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2248 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2252 // 2/0/0/2/2 2D combine blendsquare path
2253 memset(&m, 0, sizeof(m));
2254 m.pointer_vertex = vertex3f;
2255 m.tex[0] = R_GetTexture(bumptexture);
2256 m.pointer_texcoord[0] = texcoord2f;
2257 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2258 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2259 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2260 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2262 GL_ColorMask(0,0,0,1);
2263 // this squares the result
2264 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2265 GL_LockArrays(0, numverts);
2266 R_Mesh_Draw(0, numverts, numtriangles, elements);
2267 GL_LockArrays(0, 0);
2269 c_rt_lighttris += numtriangles;
2271 memset(&m, 0, sizeof(m));
2272 m.pointer_vertex = vertex3f;
2274 GL_LockArrays(0, numverts);
2275 // square alpha in framebuffer a few times to make it shiny
2276 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2277 // these comments are a test run through this math for intensity 0.5
2278 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2279 // 0.25 * 0.25 = 0.0625 (this is another pass)
2280 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2281 R_Mesh_Draw(0, numverts, numtriangles, elements);
2283 c_rt_lighttris += numtriangles;
2284 R_Mesh_Draw(0, numverts, numtriangles, elements);
2286 c_rt_lighttris += numtriangles;
2287 GL_LockArrays(0, 0);
2289 memset(&m, 0, sizeof(m));
2290 m.pointer_vertex = vertex3f;
2291 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2293 m.pointer_texcoord3f[0] = vertex3f;
2294 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2296 m.pointer_texcoord[0] = varray_texcoord2f[0];
2297 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2299 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2301 m.pointer_texcoord3f[1] = vertex3f;
2302 m.texmatrix[1] = *matrix_modeltoattenuationz;
2304 m.pointer_texcoord[1] = varray_texcoord2f[1];
2305 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2308 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2309 GL_LockArrays(0, numverts);
2310 R_Mesh_Draw(0, numverts, numtriangles, elements);
2311 GL_LockArrays(0, 0);
2313 c_rt_lighttris += numtriangles;
2315 memset(&m, 0, sizeof(m));
2316 m.pointer_vertex = vertex3f;
2317 m.tex[0] = R_GetTexture(glosstexture);
2318 m.pointer_texcoord[0] = texcoord2f;
2321 m.texcubemap[1] = R_GetTexture(lightcubemap);
2323 m.pointer_texcoord3f[1] = vertex3f;
2324 m.texmatrix[1] = *matrix_modeltolight;
2326 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2327 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2330 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2333 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2334 VectorScale(lightcolor, colorscale, color2);
2335 GL_LockArrays(0, numverts);
2336 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2338 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2339 R_Mesh_Draw(0, numverts, numtriangles, elements);
2341 c_rt_lighttris += numtriangles;
2343 GL_LockArrays(0, 0);
2351 GL_BlendFunc(GL_ONE, GL_ONE);
2352 VectorScale(lightcolor, ambientscale, color2);
2353 memset(&m, 0, sizeof(m));
2354 m.pointer_vertex = vertex3f;
2355 m.tex[0] = R_GetTexture(basetexture);
2356 m.pointer_texcoord[0] = texcoord2f;
2357 if (r_textureunits.integer >= 2)
2360 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2362 m.pointer_texcoord3f[1] = vertex3f;
2363 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2365 m.pointer_texcoord[1] = varray_texcoord2f[1];
2366 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2368 if (r_textureunits.integer >= 3)
2370 // Geforce3/Radeon class but not using dot3
2371 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2373 m.pointer_texcoord3f[2] = vertex3f;
2374 m.texmatrix[2] = *matrix_modeltoattenuationz;
2376 m.pointer_texcoord[2] = varray_texcoord2f[2];
2377 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2381 if (r_textureunits.integer >= 3)
2382 m.pointer_color = NULL;
2384 m.pointer_color = varray_color4f;
2386 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2388 color[0] = bound(0, color2[0], 1);
2389 color[1] = bound(0, color2[1], 1);
2390 color[2] = bound(0, color2[2], 1);
2391 if (r_textureunits.integer >= 3)
2392 GL_Color(color[0], color[1], color[2], 1);
2393 else if (r_textureunits.integer >= 2)
2394 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2396 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2397 GL_LockArrays(0, numverts);
2398 R_Mesh_Draw(0, numverts, numtriangles, elements);
2399 GL_LockArrays(0, 0);
2401 c_rt_lighttris += numtriangles;
2406 GL_BlendFunc(GL_ONE, GL_ONE);
2407 VectorScale(lightcolor, diffusescale, color2);
2408 memset(&m, 0, sizeof(m));
2409 m.pointer_vertex = vertex3f;
2410 m.pointer_color = varray_color4f;
2411 m.tex[0] = R_GetTexture(basetexture);
2412 m.pointer_texcoord[0] = texcoord2f;
2413 if (r_textureunits.integer >= 2)
2416 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2418 m.pointer_texcoord3f[1] = vertex3f;
2419 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2421 m.pointer_texcoord[1] = varray_texcoord2f[1];
2422 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2424 if (r_textureunits.integer >= 3)
2426 // Geforce3/Radeon class but not using dot3
2427 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2429 m.pointer_texcoord3f[2] = vertex3f;
2430 m.texmatrix[2] = *matrix_modeltoattenuationz;
2432 m.pointer_texcoord[2] = varray_texcoord2f[2];
2433 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2438 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2440 color[0] = bound(0, color2[0], 1);
2441 color[1] = bound(0, color2[1], 1);
2442 color[2] = bound(0, color2[2], 1);
2443 if (r_textureunits.integer >= 3)
2444 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2445 else if (r_textureunits.integer >= 2)
2446 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2448 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2449 GL_LockArrays(0, numverts);
2450 R_Mesh_Draw(0, numverts, numtriangles, elements);
2451 GL_LockArrays(0, 0);
2453 c_rt_lighttris += numtriangles;
2459 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2463 R_RTLight_Uncompile(rtlight);
2464 memset(rtlight, 0, sizeof(*rtlight));
2466 VectorCopy(light->origin, rtlight->shadoworigin);
2467 VectorCopy(light->color, rtlight->color);
2468 rtlight->radius = light->radius;
2469 //rtlight->cullradius = rtlight->radius;
2470 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2471 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2472 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2473 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2474 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2475 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2476 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2477 rtlight->cubemapname[0] = 0;
2478 if (light->cubemapname[0])
2479 strcpy(rtlight->cubemapname, light->cubemapname);
2480 else if (light->cubemapnum > 0)
2481 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2482 rtlight->shadow = light->shadow;
2483 rtlight->corona = light->corona;
2484 rtlight->style = light->style;
2485 rtlight->isstatic = isstatic;
2486 rtlight->coronasizescale = light->coronasizescale;
2487 rtlight->ambientscale = light->ambientscale;
2488 rtlight->diffusescale = light->diffusescale;
2489 rtlight->specularscale = light->specularscale;
2490 rtlight->flags = light->flags;
2491 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2492 // ConcatScale won't work here because this needs to scale rotate and
2493 // translate, not just rotate
2494 scale = 1.0f / rtlight->radius;
2495 for (k = 0;k < 3;k++)
2496 for (j = 0;j < 4;j++)
2497 rtlight->matrix_worldtolight.m[k][j] *= scale;
2498 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2499 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2501 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2502 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2503 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2504 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2507 // compiles rtlight geometry
2508 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2509 void R_RTLight_Compile(rtlight_t *rtlight)
2511 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2512 entity_render_t *ent = r_refdef.worldentity;
2513 model_t *model = r_refdef.worldmodel;
2515 // compile the light
2516 rtlight->compiled = true;
2517 rtlight->static_numclusters = 0;
2518 rtlight->static_numclusterpvsbytes = 0;
2519 rtlight->static_clusterlist = NULL;
2520 rtlight->static_clusterpvs = NULL;
2521 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2522 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2523 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2524 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2525 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2526 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2528 if (model && model->GetLightInfo)
2530 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2531 r_shadow_compilingrtlight = rtlight;
2532 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2533 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2534 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);
2535 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2536 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2539 rtlight->static_numclusters = numclusters;
2540 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2541 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2542 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2544 if (model->DrawShadowVolume && rtlight->shadow)
2546 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2547 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2548 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2550 if (model->DrawLight)
2552 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2553 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);
2554 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2556 // switch back to rendering when DrawShadowVolume or DrawLight is called
2557 r_shadow_compilingrtlight = NULL;
2561 // use smallest available cullradius - box radius or light radius
2562 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2563 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2567 if (rtlight->static_meshchain_shadow)
2570 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2573 shadowtris += mesh->numtriangles;
2579 if (rtlight->static_meshchain_light)
2582 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2585 lighttris += mesh->numtriangles;
2589 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);
2592 void R_RTLight_Uncompile(rtlight_t *rtlight)
2594 if (rtlight->compiled)
2596 if (rtlight->static_meshchain_shadow)
2597 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2598 rtlight->static_meshchain_shadow = NULL;
2599 if (rtlight->static_meshchain_light)
2600 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2601 rtlight->static_meshchain_light = NULL;
2602 if (rtlight->static_clusterlist)
2603 Mem_Free(rtlight->static_clusterlist);
2604 rtlight->static_clusterlist = NULL;
2605 if (rtlight->static_clusterpvs)
2606 Mem_Free(rtlight->static_clusterpvs);
2607 rtlight->static_clusterpvs = NULL;
2608 rtlight->static_numclusters = 0;
2609 rtlight->static_numclusterpvsbytes = 0;
2610 rtlight->compiled = false;
2614 void R_Shadow_UncompileWorldLights(void)
2617 for (light = r_shadow_worldlightchain;light;light = light->next)
2618 R_RTLight_Uncompile(&light->rtlight);
2621 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2623 int i, shadow, usestencil;
2624 entity_render_t *ent;
2626 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2627 rtexture_t *cubemaptexture;
2628 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2629 int numclusters, numsurfaces;
2630 int *clusterlist, *surfacelist;
2632 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2636 // skip lights that don't light (corona only lights)
2637 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2640 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2641 VectorScale(rtlight->color, f, lightcolor);
2642 if (VectorLength2(lightcolor) < 0.01)
2645 if (rtlight->selected)
2647 f = 2 + sin(realtime * M_PI * 4.0);
2648 VectorScale(lightcolor, f, lightcolor);
2652 // loading is done before visibility checks because loading should happen
2653 // all at once at the start of a level, not when it stalls gameplay.
2654 // (especially important to benchmarks)
2655 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2656 R_RTLight_Compile(rtlight);
2657 if (rtlight->cubemapname[0])
2658 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2660 cubemaptexture = NULL;
2662 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2663 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2664 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2665 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2666 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2667 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2668 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2675 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2677 // compiled light, world available and can receive realtime lighting
2678 // retrieve cluster information
2679 numclusters = rtlight->static_numclusters;
2680 clusterlist = rtlight->static_clusterlist;
2681 clusterpvs = rtlight->static_clusterpvs;
2682 VectorCopy(rtlight->cullmins, cullmins);
2683 VectorCopy(rtlight->cullmaxs, cullmaxs);
2685 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2687 // dynamic light, world available and can receive realtime lighting
2688 // if the light box is offscreen, skip it right away
2689 if (R_CullBox(cullmins, cullmaxs))
2691 // calculate lit surfaces and clusters
2692 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2693 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2694 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);
2695 clusterlist = r_shadow_buffer_clusterlist;
2696 clusterpvs = r_shadow_buffer_clusterpvs;
2697 surfacelist = r_shadow_buffer_surfacelist;
2699 // if the reduced cluster bounds are offscreen, skip it
2700 if (R_CullBox(cullmins, cullmaxs))
2702 // check if light is illuminating any visible clusters
2705 for (i = 0;i < numclusters;i++)
2706 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2708 if (i == numclusters)
2711 // set up a scissor rectangle for this light
2712 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2715 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2718 if (shadow && (gl_stencil || visiblevolumes))
2720 if (!visiblevolumes)
2722 R_Shadow_Stage_ShadowVolumes();
2725 ent = &cl_entities[0].render;
2726 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2728 memset(&m, 0, sizeof(m));
2729 R_Mesh_Matrix(&ent->matrix);
2730 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2732 m.pointer_vertex = mesh->vertex3f;
2734 GL_LockArrays(0, mesh->numverts);
2735 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2737 // increment stencil if backface is behind depthbuffer
2738 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2739 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2740 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2741 c_rtcached_shadowmeshes++;
2742 c_rtcached_shadowtris += mesh->numtriangles;
2743 // decrement stencil if frontface is behind depthbuffer
2744 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2745 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2747 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2748 c_rtcached_shadowmeshes++;
2749 c_rtcached_shadowtris += mesh->numtriangles;
2750 GL_LockArrays(0, 0);
2753 else if (numsurfaces)
2755 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2756 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2758 if (r_drawentities.integer)
2760 for (i = 0;i < r_refdef.numentities;i++)
2762 ent = r_refdef.entities[i];
2764 if (r_shadow_cull.integer)
2766 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2768 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2771 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2773 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2774 // light emitting entities should not cast their own shadow
2775 if (VectorLength2(relativelightorigin) < 0.1)
2777 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2778 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2779 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2780 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2781 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2782 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2783 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2788 if (!visiblevolumes)
2790 R_Shadow_Stage_Light(usestencil);
2792 ent = &cl_entities[0].render;
2793 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2795 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2796 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2797 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2798 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2799 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2800 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2801 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2802 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2803 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2805 R_Mesh_Matrix(&ent->matrix);
2806 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2807 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);
2810 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2812 if (r_drawentities.integer)
2814 for (i = 0;i < r_refdef.numentities;i++)
2816 ent = r_refdef.entities[i];
2817 // can't draw transparent entity lighting here because
2818 // transparent meshes are deferred for later
2819 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)
2821 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2822 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2823 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2824 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2825 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2826 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2827 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2828 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2829 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);
2836 void R_ShadowVolumeLighting(int visiblevolumes)
2842 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2843 R_Shadow_EditLights_Reload_f();
2847 memset(&m, 0, sizeof(m));
2850 GL_BlendFunc(GL_ONE, GL_ONE);
2851 GL_DepthMask(false);
2852 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2853 qglDisable(GL_CULL_FACE);
2854 GL_Color(0.0, 0.0125, 0.1, 1);
2857 R_Shadow_Stage_Begin();
2858 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2859 if (r_shadow_debuglight.integer >= 0)
2861 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2862 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2863 R_DrawRTLight(&light->rtlight, visiblevolumes);
2866 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2867 if (light->flags & flag)
2868 R_DrawRTLight(&light->rtlight, visiblevolumes);
2870 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2871 R_DrawRTLight(&light->rtlight, visiblevolumes);
2875 qglEnable(GL_CULL_FACE);
2876 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2879 R_Shadow_Stage_End();
2882 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2883 typedef struct suffixinfo_s
2886 qboolean flipx, flipy, flipdiagonal;
2889 static suffixinfo_t suffix[3][6] =
2892 {"px", false, false, false},
2893 {"nx", false, false, false},
2894 {"py", false, false, false},
2895 {"ny", false, false, false},
2896 {"pz", false, false, false},
2897 {"nz", false, false, false}
2900 {"posx", false, false, false},
2901 {"negx", false, false, false},
2902 {"posy", false, false, false},
2903 {"negy", false, false, false},
2904 {"posz", false, false, false},
2905 {"negz", false, false, false}
2908 {"rt", true, false, true},
2909 {"lf", false, true, true},
2910 {"ft", true, true, false},
2911 {"bk", false, false, false},
2912 {"up", true, false, true},
2913 {"dn", true, false, true}
2917 static int componentorder[4] = {0, 1, 2, 3};
2919 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2921 int i, j, cubemapsize;
2922 qbyte *cubemappixels, *image_rgba;
2923 rtexture_t *cubemaptexture;
2925 // must start 0 so the first loadimagepixels has no requested width/height
2927 cubemappixels = NULL;
2928 cubemaptexture = NULL;
2929 // keep trying different suffix groups (posx, px, rt) until one loads
2930 for (j = 0;j < 3 && !cubemappixels;j++)
2932 // load the 6 images in the suffix group
2933 for (i = 0;i < 6;i++)
2935 // generate an image name based on the base and and suffix
2936 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2938 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2940 // an image loaded, make sure width and height are equal
2941 if (image_width == image_height)
2943 // if this is the first image to load successfully, allocate the cubemap memory
2944 if (!cubemappixels && image_width >= 1)
2946 cubemapsize = image_width;
2947 // note this clears to black, so unavailable sides are black
2948 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2950 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2952 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);
2955 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2957 Mem_Free(image_rgba);
2961 // if a cubemap loaded, upload it
2964 if (!r_shadow_filters_texturepool)
2965 r_shadow_filters_texturepool = R_AllocTexturePool();
2966 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2967 Mem_Free(cubemappixels);
2971 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2972 for (j = 0;j < 3;j++)
2973 for (i = 0;i < 6;i++)
2974 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2975 Con_Print(" and was unable to find any of them.\n");
2977 return cubemaptexture;
2980 rtexture_t *R_Shadow_Cubemap(const char *basename)
2983 for (i = 0;i < numcubemaps;i++)
2984 if (!strcasecmp(cubemaps[i].basename, basename))
2985 return cubemaps[i].texture;
2986 if (i >= MAX_CUBEMAPS)
2989 strcpy(cubemaps[i].basename, basename);
2990 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2991 return cubemaps[i].texture;
2994 void R_Shadow_FreeCubemaps(void)
2997 R_FreeTexturePool(&r_shadow_filters_texturepool);
3000 dlight_t *R_Shadow_NewWorldLight(void)
3003 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3004 light->next = r_shadow_worldlightchain;
3005 r_shadow_worldlightchain = light;
3009 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)
3011 VectorCopy(origin, light->origin);
3012 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3013 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3014 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3015 light->color[0] = max(color[0], 0);
3016 light->color[1] = max(color[1], 0);
3017 light->color[2] = max(color[2], 0);
3018 light->radius = max(radius, 0);
3019 light->style = style;
3020 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3022 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3025 light->shadow = shadowenable;
3026 light->corona = corona;
3029 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3030 light->coronasizescale = coronasizescale;
3031 light->ambientscale = ambientscale;
3032 light->diffusescale = diffusescale;
3033 light->specularscale = specularscale;
3034 light->flags = flags;
3035 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3037 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3040 void R_Shadow_FreeWorldLight(dlight_t *light)
3042 dlight_t **lightpointer;
3043 R_RTLight_Uncompile(&light->rtlight);
3044 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3045 if (*lightpointer != light)
3046 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3047 *lightpointer = light->next;
3051 void R_Shadow_ClearWorldLights(void)
3053 while (r_shadow_worldlightchain)
3054 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3055 r_shadow_selectedlight = NULL;
3056 R_Shadow_FreeCubemaps();
3059 void R_Shadow_SelectLight(dlight_t *light)
3061 if (r_shadow_selectedlight)
3062 r_shadow_selectedlight->selected = false;
3063 r_shadow_selectedlight = light;
3064 if (r_shadow_selectedlight)
3065 r_shadow_selectedlight->selected = true;
3068 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3070 float scale = r_editlights_cursorgrid.value * 0.5f;
3071 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);
3074 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3077 const dlight_t *light;
3080 if (light->selected)
3081 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3084 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);
3087 void R_Shadow_DrawLightSprites(void)
3093 for (i = 0;i < 5;i++)
3095 lighttextures[i] = NULL;
3096 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3097 lighttextures[i] = pic->tex;
3100 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3101 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3102 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3105 void R_Shadow_SelectLightInView(void)
3107 float bestrating, rating, temp[3];
3108 dlight_t *best, *light;
3111 for (light = r_shadow_worldlightchain;light;light = light->next)
3113 VectorSubtract(light->origin, r_vieworigin, temp);
3114 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3117 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3118 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3120 bestrating = rating;
3125 R_Shadow_SelectLight(best);
3128 void R_Shadow_LoadWorldLights(void)
3130 int n, a, style, shadow, flags;
3131 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3132 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3133 if (r_refdef.worldmodel == NULL)
3135 Con_Print("No map loaded.\n");
3138 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3139 strlcat (name, ".rtlights", sizeof (name));
3140 lightsstring = FS_LoadFile(name, tempmempool, false);
3150 for (;COM_Parse(t, true) && strcmp(
3151 if (COM_Parse(t, true))
3153 if (com_token[0] == '!')
3156 origin[0] = atof(com_token+1);
3159 origin[0] = atof(com_token);
3164 while (*s && *s != '\n' && *s != '\r')
3170 // 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);
3180 flags = LIGHTFLAG_REALTIMEMODE;
3188 coronasizescale = 0.25f;
3190 VectorClear(angles);
3193 if (a < 9 || !strcmp(cubemapname, "\"\""))
3195 // remove quotes on cubemapname
3196 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3198 cubemapname[strlen(cubemapname)-1] = 0;
3199 strcpy(cubemapname, cubemapname + 1);
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);
3216 Con_Printf("invalid rtlights file \"%s\"\n", name);
3217 Mem_Free(lightsstring);
3221 void R_Shadow_SaveWorldLights(void)
3224 int bufchars, bufmaxchars;
3226 char name[MAX_QPATH];
3228 if (!r_shadow_worldlightchain)
3230 if (r_refdef.worldmodel == NULL)
3232 Con_Print("No map loaded.\n");
3235 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3236 strlcat (name, ".rtlights", sizeof (name));
3237 bufchars = bufmaxchars = 0;
3239 for (light = r_shadow_worldlightchain;light;light = light->next)
3241 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3242 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);
3243 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3244 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]);
3246 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);
3247 if (bufchars + (int) strlen(line) > bufmaxchars)
3249 bufmaxchars = bufchars + strlen(line) + 2048;
3251 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3255 memcpy(buf, oldbuf, bufchars);
3261 memcpy(buf + bufchars, line, strlen(line));
3262 bufchars += strlen(line);
3266 FS_WriteFile(name, buf, bufchars);
3271 void R_Shadow_LoadLightsFile(void)
3274 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3275 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3276 if (r_refdef.worldmodel == NULL)
3278 Con_Print("No map loaded.\n");
3281 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3282 strlcat (name, ".lights", sizeof (name));
3283 lightsstring = FS_LoadFile(name, tempmempool, false);
3291 while (*s && *s != '\n' && *s != '\r')
3297 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
3301 Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
3304 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3305 radius = bound(15, radius, 4096);
3306 VectorScale(color, (2.0f / (8388608.0f)), color);
3307 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3315 Con_Printf("invalid lights file \"%s\"\n", name);
3316 Mem_Free(lightsstring);
3320 // tyrlite/hmap2 light types in the delay field
3321 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3323 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3325 int entnum, style, islight, skin, pflags, effects, type, n;
3328 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3329 char key[256], value[1024];
3331 if (r_refdef.worldmodel == NULL)
3333 Con_Print("No map loaded.\n");
3336 // try to load a .ent file first
3337 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3338 strlcat (key, ".ent", sizeof (key));
3339 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3340 // and if that is not found, fall back to the bsp file entity string
3342 data = r_refdef.worldmodel->brush.entities;
3345 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3347 type = LIGHTTYPE_MINUSX;
3348 origin[0] = origin[1] = origin[2] = 0;
3349 originhack[0] = originhack[1] = originhack[2] = 0;
3350 angles[0] = angles[1] = angles[2] = 0;
3351 color[0] = color[1] = color[2] = 1;
3352 light[0] = light[1] = light[2] = 1;light[3] = 300;
3353 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3363 if (!COM_ParseToken(&data, false))
3365 if (com_token[0] == '}')
3366 break; // end of entity
3367 if (com_token[0] == '_')
3368 strcpy(key, com_token + 1);
3370 strcpy(key, com_token);
3371 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3372 key[strlen(key)-1] = 0;
3373 if (!COM_ParseToken(&data, false))
3375 strcpy(value, com_token);
3377 // now that we have the key pair worked out...
3378 if (!strcmp("light", key))
3380 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3384 light[0] = vec[0] * (1.0f / 256.0f);
3385 light[1] = vec[0] * (1.0f / 256.0f);
3386 light[2] = vec[0] * (1.0f / 256.0f);
3392 light[0] = vec[0] * (1.0f / 255.0f);
3393 light[1] = vec[1] * (1.0f / 255.0f);
3394 light[2] = vec[2] * (1.0f / 255.0f);
3398 else if (!strcmp("delay", key))
3400 else if (!strcmp("origin", key))
3401 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3402 else if (!strcmp("angle", key))
3403 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3404 else if (!strcmp("angles", key))
3405 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3406 else if (!strcmp("color", key))
3407 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3408 else if (!strcmp("wait", key))
3409 fadescale = atof(value);
3410 else if (!strcmp("classname", key))
3412 if (!strncmp(value, "light", 5))
3415 if (!strcmp(value, "light_fluoro"))
3420 overridecolor[0] = 1;
3421 overridecolor[1] = 1;
3422 overridecolor[2] = 1;
3424 if (!strcmp(value, "light_fluorospark"))
3429 overridecolor[0] = 1;
3430 overridecolor[1] = 1;
3431 overridecolor[2] = 1;
3433 if (!strcmp(value, "light_globe"))
3438 overridecolor[0] = 1;
3439 overridecolor[1] = 0.8;
3440 overridecolor[2] = 0.4;
3442 if (!strcmp(value, "light_flame_large_yellow"))
3447 overridecolor[0] = 1;
3448 overridecolor[1] = 0.5;
3449 overridecolor[2] = 0.1;
3451 if (!strcmp(value, "light_flame_small_yellow"))
3456 overridecolor[0] = 1;
3457 overridecolor[1] = 0.5;
3458 overridecolor[2] = 0.1;
3460 if (!strcmp(value, "light_torch_small_white"))
3465 overridecolor[0] = 1;
3466 overridecolor[1] = 0.5;
3467 overridecolor[2] = 0.1;
3469 if (!strcmp(value, "light_torch_small_walltorch"))
3474 overridecolor[0] = 1;
3475 overridecolor[1] = 0.5;
3476 overridecolor[2] = 0.1;
3480 else if (!strcmp("style", key))
3481 style = atoi(value);
3482 else if (r_refdef.worldmodel->type == mod_brushq3)
3484 if (!strcmp("scale", key))
3485 lightscale = atof(value);
3486 if (!strcmp("fade", key))
3487 fadescale = atof(value);
3489 else if (!strcmp("skin", key))
3490 skin = (int)atof(value);
3491 else if (!strcmp("pflags", key))
3492 pflags = (int)atof(value);
3493 else if (!strcmp("effects", key))
3494 effects = (int)atof(value);
3498 if (lightscale <= 0)
3502 if (color[0] == color[1] && color[0] == color[2])
3504 color[0] *= overridecolor[0];
3505 color[1] *= overridecolor[1];
3506 color[2] *= overridecolor[2];
3508 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3509 color[0] = color[0] * light[0];
3510 color[1] = color[1] * light[1];
3511 color[2] = color[2] * light[2];
3514 case LIGHTTYPE_MINUSX:
3516 case LIGHTTYPE_RECIPX:
3518 VectorScale(color, (1.0f / 16.0f), color);
3520 case LIGHTTYPE_RECIPXX:
3522 VectorScale(color, (1.0f / 16.0f), color);
3525 case LIGHTTYPE_NONE:
3529 case LIGHTTYPE_MINUSXX:
3532 VectorAdd(origin, originhack, origin);
3534 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);
3537 Mem_Free(entfiledata);
3541 void R_Shadow_SetCursorLocationForView(void)
3543 vec_t dist, push, frac;
3544 vec3_t dest, endpos, normal;
3545 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3546 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3549 dist = frac * r_editlights_cursordistance.value;
3550 push = r_editlights_cursorpushback.value;
3554 VectorMA(endpos, push, r_viewforward, endpos);
3555 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3557 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3558 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3559 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3562 void R_Shadow_UpdateWorldLightSelection(void)
3564 if (r_editlights.integer)
3566 R_Shadow_SetCursorLocationForView();
3567 R_Shadow_SelectLightInView();
3568 R_Shadow_DrawLightSprites();
3571 R_Shadow_SelectLight(NULL);
3574 void R_Shadow_EditLights_Clear_f(void)
3576 R_Shadow_ClearWorldLights();
3579 void R_Shadow_EditLights_Reload_f(void)
3581 if (!r_refdef.worldmodel)
3583 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3584 R_Shadow_ClearWorldLights();
3585 R_Shadow_LoadWorldLights();
3586 if (r_shadow_worldlightchain == NULL)
3588 R_Shadow_LoadLightsFile();
3589 if (r_shadow_worldlightchain == NULL)
3590 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3594 void R_Shadow_EditLights_Save_f(void)
3596 if (!r_refdef.worldmodel)
3598 R_Shadow_SaveWorldLights();
3601 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3603 R_Shadow_ClearWorldLights();
3604 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3607 void R_Shadow_EditLights_ImportLightsFile_f(void)
3609 R_Shadow_ClearWorldLights();
3610 R_Shadow_LoadLightsFile();
3613 void R_Shadow_EditLights_Spawn_f(void)
3616 if (!r_editlights.integer)
3618 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3621 if (Cmd_Argc() != 1)
3623 Con_Print("r_editlights_spawn does not take parameters\n");
3626 color[0] = color[1] = color[2] = 1;
3627 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3630 void R_Shadow_EditLights_Edit_f(void)
3632 vec3_t origin, angles, color;
3633 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3634 int style, shadows, flags, normalmode, realtimemode;
3635 char cubemapname[1024];
3636 if (!r_editlights.integer)
3638 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3641 if (!r_shadow_selectedlight)
3643 Con_Print("No selected light.\n");
3646 VectorCopy(r_shadow_selectedlight->origin, origin);
3647 VectorCopy(r_shadow_selectedlight->angles, angles);
3648 VectorCopy(r_shadow_selectedlight->color, color);
3649 radius = r_shadow_selectedlight->radius;
3650 style = r_shadow_selectedlight->style;
3651 if (r_shadow_selectedlight->cubemapname)
3652 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3655 shadows = r_shadow_selectedlight->shadow;
3656 corona = r_shadow_selectedlight->corona;
3657 coronasizescale = r_shadow_selectedlight->coronasizescale;
3658 ambientscale = r_shadow_selectedlight->ambientscale;
3659 diffusescale = r_shadow_selectedlight->diffusescale;
3660 specularscale = r_shadow_selectedlight->specularscale;
3661 flags = r_shadow_selectedlight->flags;
3662 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3663 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3664 if (!strcmp(Cmd_Argv(1), "origin"))
3666 if (Cmd_Argc() != 5)
3668 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3671 origin[0] = atof(Cmd_Argv(2));
3672 origin[1] = atof(Cmd_Argv(3));
3673 origin[2] = atof(Cmd_Argv(4));
3675 else if (!strcmp(Cmd_Argv(1), "originx"))
3677 if (Cmd_Argc() != 3)
3679 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3682 origin[0] = atof(Cmd_Argv(2));
3684 else if (!strcmp(Cmd_Argv(1), "originy"))
3686 if (Cmd_Argc() != 3)
3688 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3691 origin[1] = atof(Cmd_Argv(2));
3693 else if (!strcmp(Cmd_Argv(1), "originz"))
3695 if (Cmd_Argc() != 3)
3697 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3700 origin[2] = atof(Cmd_Argv(2));
3702 else if (!strcmp(Cmd_Argv(1), "move"))
3704 if (Cmd_Argc() != 5)
3706 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3709 origin[0] += atof(Cmd_Argv(2));
3710 origin[1] += atof(Cmd_Argv(3));
3711 origin[2] += atof(Cmd_Argv(4));
3713 else if (!strcmp(Cmd_Argv(1), "movex"))
3715 if (Cmd_Argc() != 3)
3717 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3720 origin[0] += atof(Cmd_Argv(2));
3722 else if (!strcmp(Cmd_Argv(1), "movey"))
3724 if (Cmd_Argc() != 3)
3726 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3729 origin[1] += atof(Cmd_Argv(2));
3731 else if (!strcmp(Cmd_Argv(1), "movez"))
3733 if (Cmd_Argc() != 3)
3735 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3738 origin[2] += atof(Cmd_Argv(2));
3740 else if (!strcmp(Cmd_Argv(1), "angles"))
3742 if (Cmd_Argc() != 5)
3744 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3747 angles[0] = atof(Cmd_Argv(2));
3748 angles[1] = atof(Cmd_Argv(3));
3749 angles[2] = atof(Cmd_Argv(4));
3751 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3753 if (Cmd_Argc() != 3)
3755 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3758 angles[0] = atof(Cmd_Argv(2));
3760 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3762 if (Cmd_Argc() != 3)
3764 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3767 angles[1] = atof(Cmd_Argv(2));
3769 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3771 if (Cmd_Argc() != 3)
3773 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3776 angles[2] = atof(Cmd_Argv(2));
3778 else if (!strcmp(Cmd_Argv(1), "color"))
3780 if (Cmd_Argc() != 5)
3782 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3785 color[0] = atof(Cmd_Argv(2));
3786 color[1] = atof(Cmd_Argv(3));
3787 color[2] = atof(Cmd_Argv(4));
3789 else if (!strcmp(Cmd_Argv(1), "radius"))
3791 if (Cmd_Argc() != 3)
3793 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3796 radius = atof(Cmd_Argv(2));
3798 else if (!strcmp(Cmd_Argv(1), "style"))
3800 if (Cmd_Argc() != 3)
3802 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3805 style = atoi(Cmd_Argv(2));
3807 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3811 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3814 if (Cmd_Argc() == 3)
3815 strcpy(cubemapname, Cmd_Argv(2));
3819 else if (!strcmp(Cmd_Argv(1), "shadows"))
3821 if (Cmd_Argc() != 3)
3823 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3826 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3828 else if (!strcmp(Cmd_Argv(1), "corona"))
3830 if (Cmd_Argc() != 3)
3832 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3835 corona = atof(Cmd_Argv(2));
3837 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3839 if (Cmd_Argc() != 3)
3841 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3844 coronasizescale = atof(Cmd_Argv(2));
3846 else if (!strcmp(Cmd_Argv(1), "ambient"))
3848 if (Cmd_Argc() != 3)
3850 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3853 ambientscale = atof(Cmd_Argv(2));
3855 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3857 if (Cmd_Argc() != 3)
3859 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3862 diffusescale = atof(Cmd_Argv(2));
3864 else if (!strcmp(Cmd_Argv(1), "specular"))
3866 if (Cmd_Argc() != 3)
3868 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3871 specularscale = atof(Cmd_Argv(2));
3873 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3875 if (Cmd_Argc() != 3)
3877 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3880 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3882 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3884 if (Cmd_Argc() != 3)
3886 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3889 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3893 Con_Print("usage: r_editlights_edit [property] [value]\n");
3894 Con_Print("Selected light's properties:\n");
3895 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3896 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3897 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3898 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3899 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3900 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3901 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3902 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3903 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3904 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3905 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3906 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3907 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3908 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3911 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3912 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3915 void R_Shadow_EditLights_EditAll_f(void)
3919 if (!r_editlights.integer)
3921 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3925 for (light = r_shadow_worldlightchain;light;light = light->next)
3927 R_Shadow_SelectLight(light);
3928 R_Shadow_EditLights_Edit_f();
3932 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3934 int lightnumber, lightcount;
3938 if (!r_editlights.integer)
3944 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3945 if (light == r_shadow_selectedlight)
3946 lightnumber = lightcount;
3947 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;
3948 if (r_shadow_selectedlight == NULL)
3950 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3951 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;
3952 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;
3953 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;
3954 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3955 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3956 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3957 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;
3958 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3959 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3960 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3961 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3962 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3963 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;
3964 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;
3967 void R_Shadow_EditLights_ToggleShadow_f(void)
3969 if (!r_editlights.integer)
3971 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3974 if (!r_shadow_selectedlight)
3976 Con_Print("No selected light.\n");
3979 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);
3982 void R_Shadow_EditLights_ToggleCorona_f(void)
3984 if (!r_editlights.integer)
3986 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3989 if (!r_shadow_selectedlight)
3991 Con_Print("No selected light.\n");
3994 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);
3997 void R_Shadow_EditLights_Remove_f(void)
3999 if (!r_editlights.integer)
4001 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4004 if (!r_shadow_selectedlight)
4006 Con_Print("No selected light.\n");
4009 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4010 r_shadow_selectedlight = NULL;
4013 void R_Shadow_EditLights_Help_f(void)
4016 "Documentation on r_editlights system:\n"
4018 "r_editlights : enable/disable editing mode\n"
4019 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4020 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4021 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4022 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4023 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4024 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4025 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4027 "r_editlights_help : this help\n"
4028 "r_editlights_clear : remove all lights\n"
4029 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4030 "r_editlights_save : save to .rtlights file\n"
4031 "r_editlights_spawn : create a light with default settings\n"
4032 "r_editlights_edit command : edit selected light - more documentation below\n"
4033 "r_editlights_remove : remove selected light\n"
4034 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4035 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4036 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4038 "origin x y z : set light location\n"
4039 "originx x: set x component of light location\n"
4040 "originy y: set y component of light location\n"
4041 "originz z: set z component of light location\n"
4042 "move x y z : adjust light location\n"
4043 "movex x: adjust x component of light location\n"
4044 "movey y: adjust y component of light location\n"
4045 "movez z: adjust z component of light location\n"
4046 "angles x y z : set light angles\n"
4047 "anglesx x: set x component of light angles\n"
4048 "anglesy y: set y component of light angles\n"
4049 "anglesz z: set z component of light angles\n"
4050 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4051 "radius radius : set radius (size) of light\n"
4052 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4053 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4054 "shadows 1/0 : turn on/off shadows\n"
4055 "corona n : set corona intensity\n"
4056 "coronasize n : set corona size (0-1)\n"
4057 "ambient n : set ambient intensity (0-1)\n"
4058 "diffuse n : set diffuse intensity (0-1)\n"
4059 "specular n : set specular intensity (0-1)\n"
4060 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4061 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4062 "<nothing> : print light properties to console\n"
4066 void R_Shadow_EditLights_CopyInfo_f(void)
4068 if (!r_editlights.integer)
4070 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4073 if (!r_shadow_selectedlight)
4075 Con_Print("No selected light.\n");
4078 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4079 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4080 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4081 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4082 if (r_shadow_selectedlight->cubemapname)
4083 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4085 r_shadow_bufferlight.cubemapname[0] = 0;
4086 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4087 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4088 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4089 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4090 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4091 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4092 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4095 void R_Shadow_EditLights_PasteInfo_f(void)
4097 if (!r_editlights.integer)
4099 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4102 if (!r_shadow_selectedlight)
4104 Con_Print("No selected light.\n");
4107 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);
4110 void R_Shadow_EditLights_Init(void)
4112 Cvar_RegisterVariable(&r_editlights);
4113 Cvar_RegisterVariable(&r_editlights_cursordistance);
4114 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4115 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4116 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4117 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4118 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4119 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4120 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4121 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4122 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4123 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4124 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4125 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4126 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4127 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4128 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4129 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4130 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4131 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4132 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4133 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);