3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
160 rtexture_t *r_shadow_blankwhitecubetexture;
161 rtexture_t *r_shadow_blankblacktexture;
163 // lights are reloaded when this changes
164 char r_shadow_mapname[MAX_QPATH];
166 // used only for light filters (cubemaps)
167 rtexturepool_t *r_shadow_filters_texturepool;
169 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
170 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
171 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
172 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
173 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
174 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
175 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
176 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
177 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
178 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
179 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
180 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
181 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
182 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
183 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
184 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
185 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
186 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
187 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
188 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
189 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
190 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
191 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
192 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
193 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
194 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
195 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
196 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
197 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
198 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
199 cvar_t r_editlights = {0, "r_editlights", "0"};
200 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
201 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
202 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
203 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
204 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
205 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
206 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
208 float r_shadow_attenpower, r_shadow_attenscale;
210 rtlight_t *r_shadow_compilingrtlight;
211 dlight_t *r_shadow_worldlightchain;
212 dlight_t *r_shadow_selectedlight;
213 dlight_t r_shadow_bufferlight;
214 vec3_t r_editlights_cursorlocation;
216 rtexture_t *lighttextures[5];
218 extern int con_vislines;
220 typedef struct cubemapinfo_s
227 #define MAX_CUBEMAPS 256
228 static int numcubemaps;
229 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
231 #define SHADERPERMUTATION_SPECULAR (1<<0)
232 #define SHADERPERMUTATION_FOG (1<<1)
233 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
234 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
235 #define SHADERPERMUTATION_COUNT (1<<4)
237 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
239 void R_Shadow_UncompileWorldLights(void);
240 void R_Shadow_ClearWorldLights(void);
241 void R_Shadow_SaveWorldLights(void);
242 void R_Shadow_LoadWorldLights(void);
243 void R_Shadow_LoadLightsFile(void);
244 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
245 void R_Shadow_EditLights_Reload_f(void);
246 void R_Shadow_ValidateCvars(void);
247 static void R_Shadow_MakeTextures(void);
248 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
250 const char *builtinshader_light_vert =
251 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
252 "// written by Forest 'LordHavoc' Hale\n"
254 "uniform vec3 LightColor;\n"
256 "#ifdef USEOFFSETMAPPING\n"
257 "uniform float OffsetMapping_Scale;\n"
258 "uniform float OffsetMapping_Bias;\n"
260 "#ifdef USESPECULAR\n"
261 "uniform float SpecularPower;\n"
264 "uniform float FogRangeRecip;\n"
266 "uniform float AmbientScale;\n"
267 "uniform float DiffuseScale;\n"
268 "#ifdef USESPECULAR\n"
269 "uniform float SpecularScale;\n"
272 "uniform sampler2D Texture_Normal;\n"
273 "uniform sampler2D Texture_Color;\n"
274 "#ifdef USESPECULAR\n"
275 "uniform sampler2D Texture_Gloss;\n"
277 "#ifdef USECUBEFILTER\n"
278 "uniform samplerCube Texture_Cube;\n"
281 "uniform sampler2D Texture_FogMask;\n"
284 "varying vec2 TexCoord;\n"
285 "varying vec3 CubeVector;\n"
286 "varying vec3 LightVector;\n"
287 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
288 "varying vec3 EyeVector;\n"
295 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
296 " // center and sharp falloff at the edge, this is about the most efficient\n"
297 " // we can get away with as far as providing illumination.\n"
299 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
300 " // provide significant illumination, large = slow = pain.\n"
301 " float colorscale = clamp(1.0 - dot(CubeVector, CubeVector), 0.0, 1.0);\n"
305 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
308 "#ifdef USEOFFSETMAPPING\n"
309 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-1, 1);\n"
310 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
311 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
312 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
313 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
314 "#define TexCoord TexCoordOffset\n"
317 " // get the texels - with a blendmap we'd need to blend multiple here\n"
318 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
319 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
320 "#ifdef USESPECULAR\n"
321 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
324 " // calculate shading\n"
325 " vec3 diffusenormal = normalize(LightVector);\n"
326 " vec3 color = colortexel * (AmbientScale + DiffuseScale * clamp(dot(surfacenormal, diffusenormal), 0.0, 1.0));\n"
327 "#ifdef USESPECULAR\n"
328 " color += glosstexel * (SpecularScale * pow(clamp(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0, 1.0), SpecularPower));\n"
331 "#ifdef USECUBEFILTER\n"
332 " // apply light cubemap filter\n"
333 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
336 " // calculate fragment color\n"
337 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
341 const char *builtinshader_light_frag =
342 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
343 "// written by Forest 'LordHavoc' Hale\n"
345 "uniform vec3 LightColor;\n"
347 "#ifdef USEOFFSETMAPPING\n"
348 "uniform float OffsetMapping_Scale;\n"
349 "uniform float OffsetMapping_Bias;\n"
351 "#ifdef USESPECULAR\n"
352 "uniform float SpecularPower;\n"
355 "uniform float FogRangeRecip;\n"
357 "uniform float AmbientScale;\n"
358 "uniform float DiffuseScale;\n"
359 "#ifdef USESPECULAR\n"
360 "uniform float SpecularScale;\n"
363 "uniform sampler2D Texture_Normal;\n"
364 "uniform sampler2D Texture_Color;\n"
365 "#ifdef USESPECULAR\n"
366 "uniform sampler2D Texture_Gloss;\n"
368 "#ifdef USECUBEFILTER\n"
369 "uniform samplerCube Texture_Cube;\n"
372 "uniform sampler2D Texture_FogMask;\n"
375 "varying vec2 TexCoord;\n"
376 "varying vec3 CubeVector;\n"
377 "varying vec3 LightVector;\n"
378 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
379 "varying vec3 EyeVector;\n"
386 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
387 " // center and sharp falloff at the edge, this is about the most efficient\n"
388 " // we can get away with as far as providing illumination.\n"
390 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
391 " // provide significant illumination, large = slow = pain.\n"
392 " float colorscale = clamp(1.0 - dot(CubeVector, CubeVector), 0.0, 1.0);\n"
396 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
399 "#ifdef USEOFFSETMAPPING\n"
400 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-1, 1);\n"
401 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
402 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
403 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
404 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
407 "#ifdef USECUBEFILTER\n"
408 " // apply light cubemap filter\n"
409 " LightColor *= vec3(textureCube(Texture_Cube, CubeVector));\n"
412 " // get the texels - with a blendmap we'd need to blend multiple here\n"
413 " vec3 surfacenormal = vec3(texture2D(Texture_Normal, TexCoord)) * 2.0 - 1.0;\n"
414 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
415 "#ifdef USESPECULAR\n"
416 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
419 " // calculate shading\n"
420 " vec3 diffusenormal = normalize(LightVector);\n"
421 " vec3 color = colortexel * (AmbientScale + DiffuseScale * clamp(dot(surfacenormal, diffusenormal), 0.0, 1.0));\n"
422 "#ifdef USESPECULAR\n"
423 " color += glosstexel * (SpecularScale * pow(clamp(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0, 1.0), SpecularPower));\n"
426 " // calculate fragment color\n"
427 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
431 void r_shadow_start(void)
434 // allocate vertex processing arrays
436 r_shadow_normalcubetexture = NULL;
437 r_shadow_attenuation2dtexture = NULL;
438 r_shadow_attenuation3dtexture = NULL;
439 r_shadow_blankbumptexture = NULL;
440 r_shadow_blankglosstexture = NULL;
441 r_shadow_blankwhitetexture = NULL;
442 r_shadow_blankwhitecubetexture = NULL;
443 r_shadow_blankblacktexture = NULL;
444 r_shadow_texturepool = NULL;
445 r_shadow_filters_texturepool = NULL;
446 R_Shadow_ValidateCvars();
447 R_Shadow_MakeTextures();
448 maxshadowelements = 0;
449 shadowelements = NULL;
457 shadowmarklist = NULL;
459 r_shadow_buffer_numclusterpvsbytes = 0;
460 r_shadow_buffer_clusterpvs = NULL;
461 r_shadow_buffer_clusterlist = NULL;
462 r_shadow_buffer_numsurfacepvsbytes = 0;
463 r_shadow_buffer_surfacepvs = NULL;
464 r_shadow_buffer_surfacelist = NULL;
465 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
466 r_shadow_program_light[i] = 0;
467 if (gl_support_fragment_shader)
469 char *vertstring, *fragstring;
470 int vertstrings_count;
471 int fragstrings_count;
472 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
473 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
474 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
475 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
476 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
478 vertstrings_count = 0;
479 fragstrings_count = 0;
480 if (i & SHADERPERMUTATION_SPECULAR)
482 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
483 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
485 if (i & SHADERPERMUTATION_FOG)
487 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
488 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
490 if (i & SHADERPERMUTATION_CUBEFILTER)
492 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
493 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
495 if (i & SHADERPERMUTATION_OFFSETMAPPING)
497 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
498 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
500 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
501 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
502 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
503 qglUseProgramObjectARB(r_shadow_program_light[i]);
504 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
505 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
506 if (i & SHADERPERMUTATION_SPECULAR)
508 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
510 if (i & SHADERPERMUTATION_CUBEFILTER)
512 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
514 if (i & SHADERPERMUTATION_FOG)
516 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
519 qglUseProgramObjectARB(0);
521 Mem_Free(fragstring);
523 Mem_Free(vertstring);
527 void r_shadow_shutdown(void)
530 R_Shadow_UncompileWorldLights();
531 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
533 if (r_shadow_program_light[i])
535 GL_Backend_FreeProgram(r_shadow_program_light[i]);
536 r_shadow_program_light[i] = 0;
540 r_shadow_normalcubetexture = NULL;
541 r_shadow_attenuation2dtexture = NULL;
542 r_shadow_attenuation3dtexture = NULL;
543 r_shadow_blankbumptexture = NULL;
544 r_shadow_blankglosstexture = NULL;
545 r_shadow_blankwhitetexture = NULL;
546 r_shadow_blankwhitecubetexture = NULL;
547 r_shadow_blankblacktexture = NULL;
548 R_FreeTexturePool(&r_shadow_texturepool);
549 R_FreeTexturePool(&r_shadow_filters_texturepool);
550 maxshadowelements = 0;
552 Mem_Free(shadowelements);
553 shadowelements = NULL;
556 Mem_Free(vertexupdate);
559 Mem_Free(vertexremap);
565 Mem_Free(shadowmark);
568 Mem_Free(shadowmarklist);
569 shadowmarklist = NULL;
571 r_shadow_buffer_numclusterpvsbytes = 0;
572 if (r_shadow_buffer_clusterpvs)
573 Mem_Free(r_shadow_buffer_clusterpvs);
574 r_shadow_buffer_clusterpvs = NULL;
575 if (r_shadow_buffer_clusterlist)
576 Mem_Free(r_shadow_buffer_clusterlist);
577 r_shadow_buffer_clusterlist = NULL;
578 r_shadow_buffer_numsurfacepvsbytes = 0;
579 if (r_shadow_buffer_surfacepvs)
580 Mem_Free(r_shadow_buffer_surfacepvs);
581 r_shadow_buffer_surfacepvs = NULL;
582 if (r_shadow_buffer_surfacelist)
583 Mem_Free(r_shadow_buffer_surfacelist);
584 r_shadow_buffer_surfacelist = NULL;
587 void r_shadow_newmap(void)
591 void R_Shadow_Help_f(void)
594 "Documentation on r_shadow system:\n"
596 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
597 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
598 "r_shadow_debuglight : render only this light number (-1 = all)\n"
599 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
600 "r_shadow_gloss2intensity : brightness of forced gloss\n"
601 "r_shadow_glossintensity : brightness of textured gloss\n"
602 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
603 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
604 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
605 "r_shadow_portallight : use portal visibility for static light precomputation\n"
606 "r_shadow_projectdistance : shadow volume projection distance\n"
607 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
608 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
609 "r_shadow_realtime_world : use high quality world lighting mode\n"
610 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
611 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
612 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
613 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
614 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
615 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
616 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
617 "r_shadow_scissor : use scissor optimization\n"
618 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
619 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
620 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
621 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
622 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
624 "r_shadow_help : this help\n"
628 void R_Shadow_Init(void)
630 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
631 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
632 Cvar_RegisterVariable(&r_shadow_cull);
633 Cvar_RegisterVariable(&r_shadow_debuglight);
634 Cvar_RegisterVariable(&r_shadow_gloss);
635 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
636 Cvar_RegisterVariable(&r_shadow_glossintensity);
637 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
638 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
639 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
640 Cvar_RegisterVariable(&r_shadow_portallight);
641 Cvar_RegisterVariable(&r_shadow_projectdistance);
642 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
643 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
644 Cvar_RegisterVariable(&r_shadow_realtime_world);
645 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
646 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
647 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
648 Cvar_RegisterVariable(&r_shadow_scissor);
649 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
650 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
651 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
652 Cvar_RegisterVariable(&r_shadow_staticworldlights);
653 Cvar_RegisterVariable(&r_shadow_texture3d);
654 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
655 Cvar_RegisterVariable(&r_shadow_glsl);
656 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
657 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
658 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
659 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
660 if (gamemode == GAME_TENEBRAE)
662 Cvar_SetValue("r_shadow_gloss", 2);
663 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
665 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
666 R_Shadow_EditLights_Init();
667 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
668 r_shadow_worldlightchain = NULL;
669 maxshadowelements = 0;
670 shadowelements = NULL;
678 shadowmarklist = NULL;
680 r_shadow_buffer_numclusterpvsbytes = 0;
681 r_shadow_buffer_clusterpvs = NULL;
682 r_shadow_buffer_clusterlist = NULL;
683 r_shadow_buffer_numsurfacepvsbytes = 0;
684 r_shadow_buffer_surfacepvs = NULL;
685 r_shadow_buffer_surfacelist = NULL;
686 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
689 matrix4x4_t matrix_attenuationxyz =
692 {0.5, 0.0, 0.0, 0.5},
693 {0.0, 0.5, 0.0, 0.5},
694 {0.0, 0.0, 0.5, 0.5},
699 matrix4x4_t matrix_attenuationz =
702 {0.0, 0.0, 0.5, 0.5},
703 {0.0, 0.0, 0.0, 0.5},
704 {0.0, 0.0, 0.0, 0.5},
709 int *R_Shadow_ResizeShadowElements(int numtris)
711 // make sure shadowelements is big enough for this volume
712 if (maxshadowelements < numtris * 24)
714 maxshadowelements = numtris * 24;
716 Mem_Free(shadowelements);
717 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
719 return shadowelements;
722 void R_Shadow_EnlargeClusterBuffer(int numclusters)
724 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
725 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
727 if (r_shadow_buffer_clusterpvs)
728 Mem_Free(r_shadow_buffer_clusterpvs);
729 if (r_shadow_buffer_clusterlist)
730 Mem_Free(r_shadow_buffer_clusterlist);
731 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
732 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
733 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
737 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
739 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
740 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
742 if (r_shadow_buffer_surfacepvs)
743 Mem_Free(r_shadow_buffer_surfacepvs);
744 if (r_shadow_buffer_surfacelist)
745 Mem_Free(r_shadow_buffer_surfacelist);
746 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
747 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
748 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
752 void R_Shadow_PrepareShadowMark(int numtris)
754 // make sure shadowmark is big enough for this volume
755 if (maxshadowmark < numtris)
757 maxshadowmark = numtris;
759 Mem_Free(shadowmark);
761 Mem_Free(shadowmarklist);
762 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
763 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
767 // if shadowmarkcount wrapped we clear the array and adjust accordingly
768 if (shadowmarkcount == 0)
771 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
776 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)
778 int i, j, tris = 0, vr[3], t, outvertices = 0;
783 if (maxvertexupdate < innumvertices)
785 maxvertexupdate = innumvertices;
787 Mem_Free(vertexupdate);
789 Mem_Free(vertexremap);
790 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
791 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
795 if (vertexupdatenum == 0)
798 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
799 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
802 for (i = 0;i < numshadowmarktris;i++)
803 shadowmark[shadowmarktris[i]] = shadowmarkcount;
805 for (i = 0;i < numshadowmarktris;i++)
807 t = shadowmarktris[i];
808 e = inelement3i + t * 3;
809 // make sure the vertices are created
810 for (j = 0;j < 3;j++)
812 if (vertexupdate[e[j]] != vertexupdatenum)
814 vertexupdate[e[j]] = vertexupdatenum;
815 vertexremap[e[j]] = outvertices;
816 v = invertex3f + e[j] * 3;
817 // project one copy of the vertex to the sphere radius of the light
818 // (FIXME: would projecting it to the light box be better?)
819 VectorSubtract(v, projectorigin, temp);
820 f = projectdistance / VectorLength(temp);
821 VectorCopy(v, outvertex3f);
822 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
829 for (i = 0;i < numshadowmarktris;i++)
831 t = shadowmarktris[i];
832 e = inelement3i + t * 3;
833 n = inneighbor3i + t * 3;
834 // output the front and back triangles
835 outelement3i[0] = vertexremap[e[0]];
836 outelement3i[1] = vertexremap[e[1]];
837 outelement3i[2] = vertexremap[e[2]];
838 outelement3i[3] = vertexremap[e[2]] + 1;
839 outelement3i[4] = vertexremap[e[1]] + 1;
840 outelement3i[5] = vertexremap[e[0]] + 1;
843 // output the sides (facing outward from this triangle)
844 if (shadowmark[n[0]] != shadowmarkcount)
846 vr[0] = vertexremap[e[0]];
847 vr[1] = vertexremap[e[1]];
848 outelement3i[0] = vr[1];
849 outelement3i[1] = vr[0];
850 outelement3i[2] = vr[0] + 1;
851 outelement3i[3] = vr[1];
852 outelement3i[4] = vr[0] + 1;
853 outelement3i[5] = vr[1] + 1;
857 if (shadowmark[n[1]] != shadowmarkcount)
859 vr[1] = vertexremap[e[1]];
860 vr[2] = vertexremap[e[2]];
861 outelement3i[0] = vr[2];
862 outelement3i[1] = vr[1];
863 outelement3i[2] = vr[1] + 1;
864 outelement3i[3] = vr[2];
865 outelement3i[4] = vr[1] + 1;
866 outelement3i[5] = vr[2] + 1;
870 if (shadowmark[n[2]] != shadowmarkcount)
872 vr[0] = vertexremap[e[0]];
873 vr[2] = vertexremap[e[2]];
874 outelement3i[0] = vr[0];
875 outelement3i[1] = vr[2];
876 outelement3i[2] = vr[2] + 1;
877 outelement3i[3] = vr[0];
878 outelement3i[4] = vr[2] + 1;
879 outelement3i[5] = vr[0] + 1;
885 *outnumvertices = outvertices;
889 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)
892 if (projectdistance < 0.1)
894 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
897 if (!numverts || !nummarktris)
899 // make sure shadowelements is big enough for this volume
900 if (maxshadowelements < nummarktris * 24)
901 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
902 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
903 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
906 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs)
911 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
913 tend = firsttriangle + numtris;
914 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
915 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
916 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
918 // surface box entirely inside light box, no box cull
919 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
920 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
921 shadowmarklist[numshadowmark++] = t;
925 // surface box not entirely inside light box, cull each triangle
926 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
928 v[0] = invertex3f + e[0] * 3;
929 v[1] = invertex3f + e[1] * 3;
930 v[2] = invertex3f + e[2] * 3;
931 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
932 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
933 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
934 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
935 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
936 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
937 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
938 shadowmarklist[numshadowmark++] = t;
943 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
946 if (r_shadow_compilingrtlight)
948 // if we're compiling an rtlight, capture the mesh
949 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
952 memset(&m, 0, sizeof(m));
953 m.pointer_vertex = vertex3f;
955 GL_LockArrays(0, numvertices);
956 if (r_shadowstage == SHADOWSTAGE_STENCIL)
958 // increment stencil if backface is behind depthbuffer
959 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
960 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
961 R_Mesh_Draw(numvertices, numtriangles, element3i);
963 c_rt_shadowtris += numtriangles;
964 // decrement stencil if frontface is behind depthbuffer
965 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
966 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
968 R_Mesh_Draw(numvertices, numtriangles, element3i);
970 c_rt_shadowtris += numtriangles;
974 static void R_Shadow_MakeTextures(void)
976 int x, y, z, d, side;
977 float v[3], s, t, intensity;
979 R_FreeTexturePool(&r_shadow_texturepool);
980 r_shadow_texturepool = R_AllocTexturePool();
981 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
982 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
984 #define ATTEN2DSIZE 64
985 #define ATTEN3DSIZE 32
986 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
987 data[0] = 128; // normal X
988 data[1] = 128; // normal Y
989 data[2] = 255; // normal Z
990 data[3] = 128; // height
991 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
996 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
1001 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
1006 r_shadow_blankblacktexture = R_LoadTexture2D(r_shadow_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
1007 r_shadow_blankwhitecubetexture = NULL;
1008 r_shadow_normalcubetexture = NULL;
1009 if (gl_texturecubemap)
1011 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
1012 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
1013 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
1014 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
1015 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
1016 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
1017 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1018 for (side = 0;side < 6;side++)
1020 for (y = 0;y < NORMSIZE;y++)
1022 for (x = 0;x < NORMSIZE;x++)
1024 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1025 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1059 intensity = 127.0f / sqrt(DotProduct(v, v));
1060 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1061 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1062 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1063 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1067 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1069 for (y = 0;y < ATTEN2DSIZE;y++)
1071 for (x = 0;x < ATTEN2DSIZE;x++)
1073 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1074 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1076 intensity = 1.0f - sqrt(DotProduct(v, v));
1078 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1079 d = bound(0, intensity, 255);
1080 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1081 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1082 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1083 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1086 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1087 if (r_shadow_texture3d.integer)
1089 for (z = 0;z < ATTEN3DSIZE;z++)
1091 for (y = 0;y < ATTEN3DSIZE;y++)
1093 for (x = 0;x < ATTEN3DSIZE;x++)
1095 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1096 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1097 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1098 intensity = 1.0f - sqrt(DotProduct(v, v));
1100 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1101 d = bound(0, intensity, 255);
1102 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1103 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1104 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1105 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1109 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1114 void R_Shadow_ValidateCvars(void)
1116 if (r_shadow_texture3d.integer && !gl_texture3d)
1117 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1118 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1119 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1122 void R_Shadow_Stage_Begin(void)
1126 R_Shadow_ValidateCvars();
1128 if (!r_shadow_attenuation2dtexture
1129 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1130 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1131 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1132 R_Shadow_MakeTextures();
1134 memset(&m, 0, sizeof(m));
1135 GL_BlendFunc(GL_ONE, GL_ZERO);
1136 GL_DepthMask(false);
1139 GL_Color(0, 0, 0, 1);
1140 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1141 qglEnable(GL_CULL_FACE);
1142 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1143 r_shadowstage = SHADOWSTAGE_NONE;
1146 void R_Shadow_Stage_ShadowVolumes(void)
1149 memset(&m, 0, sizeof(m));
1151 GL_Color(1, 1, 1, 1);
1152 GL_ColorMask(0, 0, 0, 0);
1153 GL_BlendFunc(GL_ONE, GL_ZERO);
1154 GL_DepthMask(false);
1156 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1157 //if (r_shadow_shadow_polygonoffset.value != 0)
1159 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1160 // qglEnable(GL_POLYGON_OFFSET_FILL);
1163 // qglDisable(GL_POLYGON_OFFSET_FILL);
1164 qglDepthFunc(GL_LESS);
1165 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1166 qglEnable(GL_STENCIL_TEST);
1167 qglStencilFunc(GL_ALWAYS, 128, ~0);
1168 if (gl_ext_stenciltwoside.integer)
1170 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1171 qglDisable(GL_CULL_FACE);
1172 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1173 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1175 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1176 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1178 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1182 r_shadowstage = SHADOWSTAGE_STENCIL;
1183 qglEnable(GL_CULL_FACE);
1185 // this is changed by every shadow render so its value here is unimportant
1186 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1188 GL_Clear(GL_STENCIL_BUFFER_BIT);
1190 // LordHavoc note: many shadow volumes reside entirely inside the world
1191 // (that is to say they are entirely bounded by their lit surfaces),
1192 // which can be optimized by handling things as an inverted light volume,
1193 // with the shadow boundaries of the world being simulated by an altered
1194 // (129) bias to stencil clearing on such lights
1195 // FIXME: generate inverted light volumes for use as shadow volumes and
1196 // optimize for them as noted above
1199 void R_Shadow_Stage_Light(int shadowtest)
1202 memset(&m, 0, sizeof(m));
1204 GL_BlendFunc(GL_ONE, GL_ONE);
1205 GL_DepthMask(false);
1207 qglPolygonOffset(0, 0);
1208 //qglDisable(GL_POLYGON_OFFSET_FILL);
1209 GL_Color(1, 1, 1, 1);
1210 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1211 qglDepthFunc(GL_EQUAL);
1212 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1213 qglEnable(GL_CULL_FACE);
1215 qglEnable(GL_STENCIL_TEST);
1217 qglDisable(GL_STENCIL_TEST);
1218 if (gl_support_stenciltwoside)
1219 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1221 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1222 // only draw light where this geometry was already rendered AND the
1223 // stencil is 128 (values other than this mean shadow)
1224 qglStencilFunc(GL_EQUAL, 128, ~0);
1225 r_shadowstage = SHADOWSTAGE_LIGHT;
1229 void R_Shadow_Stage_End(void)
1232 memset(&m, 0, sizeof(m));
1234 GL_BlendFunc(GL_ONE, GL_ZERO);
1237 qglPolygonOffset(0, 0);
1238 //qglDisable(GL_POLYGON_OFFSET_FILL);
1239 GL_Color(1, 1, 1, 1);
1240 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1241 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1242 qglDepthFunc(GL_LEQUAL);
1243 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1244 qglDisable(GL_STENCIL_TEST);
1245 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1246 if (gl_support_stenciltwoside)
1247 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1249 qglStencilFunc(GL_ALWAYS, 128, ~0);
1250 r_shadowstage = SHADOWSTAGE_NONE;
1253 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1255 int i, ix1, iy1, ix2, iy2;
1256 float x1, y1, x2, y2, x, y, f;
1257 vec3_t smins, smaxs;
1259 if (!r_shadow_scissor.integer)
1261 // if view is inside the box, just say yes it's visible
1262 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1264 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1267 for (i = 0;i < 3;i++)
1269 if (r_viewforward[i] >= 0)
1280 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1281 if (DotProduct(r_viewforward, v2) <= f)
1283 // entirely behind nearclip plane
1286 if (DotProduct(r_viewforward, v) >= f)
1288 // entirely infront of nearclip plane
1289 x1 = y1 = x2 = y2 = 0;
1290 for (i = 0;i < 8;i++)
1292 v[0] = (i & 1) ? mins[0] : maxs[0];
1293 v[1] = (i & 2) ? mins[1] : maxs[1];
1294 v[2] = (i & 4) ? mins[2] : maxs[2];
1296 GL_TransformToScreen(v, v2);
1297 //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]);
1316 // clipped by nearclip plane
1317 // this is nasty and crude...
1318 // create viewspace bbox
1319 for (i = 0;i < 8;i++)
1321 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1322 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1323 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1324 v2[0] = -DotProduct(v, r_viewleft);
1325 v2[1] = DotProduct(v, r_viewup);
1326 v2[2] = DotProduct(v, r_viewforward);
1329 if (smins[0] > v2[0]) smins[0] = v2[0];
1330 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1331 if (smins[1] > v2[1]) smins[1] = v2[1];
1332 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1333 if (smins[2] > v2[2]) smins[2] = v2[2];
1334 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1338 smins[0] = smaxs[0] = v2[0];
1339 smins[1] = smaxs[1] = v2[1];
1340 smins[2] = smaxs[2] = v2[2];
1343 // now we have a bbox in viewspace
1344 // clip it to the view plane
1347 // return true if that culled the box
1348 if (smins[2] >= smaxs[2])
1350 // ok some of it is infront of the view, transform each corner back to
1351 // worldspace and then to screenspace and make screen rect
1352 // initialize these variables just to avoid compiler warnings
1353 x1 = y1 = x2 = y2 = 0;
1354 for (i = 0;i < 8;i++)
1356 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1357 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1358 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1359 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1360 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1361 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1363 GL_TransformToScreen(v, v2);
1364 //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]);
1381 // this code doesn't handle boxes with any points behind view properly
1382 x1 = 1000;x2 = -1000;
1383 y1 = 1000;y2 = -1000;
1384 for (i = 0;i < 8;i++)
1386 v[0] = (i & 1) ? mins[0] : maxs[0];
1387 v[1] = (i & 2) ? mins[1] : maxs[1];
1388 v[2] = (i & 4) ? mins[2] : maxs[2];
1390 GL_TransformToScreen(v, v2);
1391 //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]);
1409 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1410 if (ix1 < r_view_x) ix1 = r_view_x;
1411 if (iy1 < r_view_y) iy1 = r_view_y;
1412 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1413 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1414 if (ix2 <= ix1 || iy2 <= iy1)
1416 // set up the scissor rectangle
1417 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1418 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1419 //qglEnable(GL_SCISSOR_TEST);
1424 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1426 float *color4f = varray_color4f;
1427 float dist, dot, intensity, v[3], n[3];
1428 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1430 Matrix4x4_Transform(m, vertex3f, v);
1431 if ((dist = DotProduct(v, v)) < 1)
1433 Matrix4x4_Transform3x3(m, normal3f, n);
1434 if ((dot = DotProduct(n, v)) > 0)
1437 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1438 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1439 VectorScale(lightcolor, intensity, color4f);
1444 VectorClear(color4f);
1450 VectorClear(color4f);
1456 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1458 float *color4f = varray_color4f;
1459 float dist, dot, intensity, v[3], n[3];
1460 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1462 Matrix4x4_Transform(m, vertex3f, v);
1463 if ((dist = fabs(v[2])) < 1)
1465 Matrix4x4_Transform3x3(m, normal3f, n);
1466 if ((dot = DotProduct(n, v)) > 0)
1468 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1469 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1470 VectorScale(lightcolor, intensity, color4f);
1475 VectorClear(color4f);
1481 VectorClear(color4f);
1487 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1489 float *color4f = varray_color4f;
1490 float dot, intensity, v[3], n[3];
1491 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1493 Matrix4x4_Transform(m, vertex3f, v);
1494 Matrix4x4_Transform3x3(m, normal3f, n);
1495 if ((dot = DotProduct(n, v)) > 0)
1497 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1498 VectorScale(lightcolor, intensity, color4f);
1503 VectorClear(color4f);
1509 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1511 float *color4f = varray_color4f;
1512 float dist, intensity, v[3];
1513 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1515 Matrix4x4_Transform(m, vertex3f, v);
1516 if ((dist = DotProduct(v, v)) < 1)
1519 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1520 VectorScale(lightcolor, intensity, color4f);
1525 VectorClear(color4f);
1531 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1533 float *color4f = varray_color4f;
1534 float dist, intensity, v[3];
1535 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1537 Matrix4x4_Transform(m, vertex3f, v);
1538 if ((dist = fabs(v[2])) < 1)
1540 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1541 VectorScale(lightcolor, intensity, color4f);
1546 VectorClear(color4f);
1552 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1553 #define USETEXMATRIX
1555 #ifndef USETEXMATRIX
1556 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1557 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1558 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1562 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1563 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1564 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1571 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1575 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1576 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1584 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)
1588 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1590 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1591 // the cubemap normalizes this for us
1592 out3f[0] = DotProduct(svector3f, lightdir);
1593 out3f[1] = DotProduct(tvector3f, lightdir);
1594 out3f[2] = DotProduct(normal3f, lightdir);
1598 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)
1601 float lightdir[3], eyedir[3], halfdir[3];
1602 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1604 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1605 VectorNormalizeFast(lightdir);
1606 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1607 VectorNormalizeFast(eyedir);
1608 VectorAdd(lightdir, eyedir, halfdir);
1609 // the cubemap normalizes this for us
1610 out3f[0] = DotProduct(svector3f, halfdir);
1611 out3f[1] = DotProduct(tvector3f, halfdir);
1612 out3f[2] = DotProduct(normal3f, halfdir);
1616 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)
1619 float color[3], color2[3], colorscale;
1621 // FIXME: support EF_NODEPTHTEST
1622 GL_DepthMask(false);
1625 bumptexture = r_shadow_blankbumptexture;
1626 specularscale *= r_shadow_glossintensity.value;
1629 if (r_shadow_gloss.integer >= 2)
1631 glosstexture = r_shadow_blankglosstexture;
1632 specularscale *= r_shadow_gloss2intensity.value;
1636 glosstexture = r_shadow_blankblacktexture;
1640 if (r_shadow_gloss.integer < 1)
1643 lightcubemap = r_shadow_blankwhitecubetexture;
1644 if (ambientscale + diffusescale + specularscale < 0.01)
1646 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1648 unsigned int perm, prog;
1649 // GLSL shader path (GFFX5200, Radeon 9500)
1650 memset(&m, 0, sizeof(m));
1651 m.pointer_vertex = vertex3f;
1652 m.pointer_texcoord[0] = texcoord2f;
1653 m.pointer_texcoord3f[1] = svector3f;
1654 m.pointer_texcoord3f[2] = tvector3f;
1655 m.pointer_texcoord3f[3] = normal3f;
1656 m.tex[0] = R_GetTexture(bumptexture);
1657 m.tex[1] = R_GetTexture(basetexture);
1658 m.tex[2] = R_GetTexture(glosstexture);
1659 m.texcubemap[3] = R_GetTexture(lightcubemap);
1660 // TODO: support fog (after renderer is converted to texture fog)
1661 m.tex[4] = R_GetTexture(r_shadow_blankwhitetexture);
1662 m.texmatrix[3] = *matrix_modeltolight;
1664 GL_BlendFunc(GL_ONE, GL_ONE);
1665 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1669 perm |= SHADERPERMUTATION_SPECULAR;
1671 // perm |= SHADERPERMUTATION_FOG;
1673 perm |= SHADERPERMUTATION_CUBEFILTER;
1674 if (r_shadow_glsl_offsetmapping.integer)
1675 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1676 prog = r_shadow_program_light[perm];
1677 qglUseProgramObjectARB(r_shadow_program_light[perm]);CHECKGLERROR
1678 // TODO: support fog (after renderer is converted to texture fog)
1679 if (perm & SHADERPERMUTATION_FOG)
1681 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1683 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1684 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1685 if (perm & SHADERPERMUTATION_SPECULAR)
1687 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1688 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1690 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);CHECKGLERROR
1691 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1692 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1694 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1696 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1698 // these are * 0.25 because the offsetmapping shader does the process 4 times
1699 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value * 0.25);CHECKGLERROR
1700 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value * 0.25);CHECKGLERROR
1703 GL_LockArrays(0, numverts);
1704 R_Mesh_Draw(numverts, numtriangles, elements);
1706 c_rt_lighttris += numtriangles;
1707 GL_LockArrays(0, 0);
1708 qglUseProgramObjectARB(0);
1709 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1710 qglBegin(GL_TRIANGLES);
1714 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1717 bumptexture = r_shadow_blankbumptexture;
1719 glosstexture = r_shadow_blankglosstexture;
1723 colorscale = ambientscale;
1724 // colorscale accounts for how much we multiply the brightness
1727 // mult is how many times the final pass of the lighting will be
1728 // performed to get more brightness than otherwise possible.
1730 // Limit mult to 64 for sanity sake.
1731 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1733 // 3 3D combine path (Geforce3, Radeon 8500)
1734 memset(&m, 0, sizeof(m));
1735 m.pointer_vertex = vertex3f;
1736 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1738 m.pointer_texcoord3f[0] = vertex3f;
1739 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1741 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1742 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1744 m.tex[1] = R_GetTexture(basetexture);
1745 m.pointer_texcoord[1] = texcoord2f;
1746 m.texcubemap[2] = R_GetTexture(lightcubemap);
1748 m.pointer_texcoord3f[2] = vertex3f;
1749 m.texmatrix[2] = *matrix_modeltolight;
1751 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1752 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1754 GL_BlendFunc(GL_ONE, GL_ONE);
1756 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1758 // 2 3D combine path (Geforce3, original Radeon)
1759 memset(&m, 0, sizeof(m));
1760 m.pointer_vertex = vertex3f;
1761 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1763 m.pointer_texcoord3f[0] = vertex3f;
1764 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1766 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1767 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1769 m.tex[1] = R_GetTexture(basetexture);
1770 m.pointer_texcoord[1] = texcoord2f;
1771 GL_BlendFunc(GL_ONE, GL_ONE);
1773 else if (r_textureunits.integer >= 4 && lightcubemap)
1775 // 4 2D combine path (Geforce3, Radeon 8500)
1776 memset(&m, 0, sizeof(m));
1777 m.pointer_vertex = vertex3f;
1778 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1780 m.pointer_texcoord3f[0] = vertex3f;
1781 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1783 m.pointer_texcoord[0] = varray_texcoord2f[0];
1784 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1786 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1788 m.pointer_texcoord3f[1] = vertex3f;
1789 m.texmatrix[1] = *matrix_modeltoattenuationz;
1791 m.pointer_texcoord[1] = varray_texcoord2f[1];
1792 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1794 m.tex[2] = R_GetTexture(basetexture);
1795 m.pointer_texcoord[2] = texcoord2f;
1798 m.texcubemap[3] = R_GetTexture(lightcubemap);
1800 m.pointer_texcoord3f[3] = vertex3f;
1801 m.texmatrix[3] = *matrix_modeltolight;
1803 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1804 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1807 GL_BlendFunc(GL_ONE, GL_ONE);
1809 else if (r_textureunits.integer >= 3 && !lightcubemap)
1811 // 3 2D combine path (Geforce3, original Radeon)
1812 memset(&m, 0, sizeof(m));
1813 m.pointer_vertex = vertex3f;
1814 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1816 m.pointer_texcoord3f[0] = vertex3f;
1817 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1819 m.pointer_texcoord[0] = varray_texcoord2f[0];
1820 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1822 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1824 m.pointer_texcoord3f[1] = vertex3f;
1825 m.texmatrix[1] = *matrix_modeltoattenuationz;
1827 m.pointer_texcoord[1] = varray_texcoord2f[1];
1828 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1830 m.tex[2] = R_GetTexture(basetexture);
1831 m.pointer_texcoord[2] = texcoord2f;
1832 GL_BlendFunc(GL_ONE, GL_ONE);
1836 // 2/2/2 2D combine path (any dot3 card)
1837 memset(&m, 0, sizeof(m));
1838 m.pointer_vertex = vertex3f;
1839 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1841 m.pointer_texcoord3f[0] = vertex3f;
1842 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1844 m.pointer_texcoord[0] = varray_texcoord2f[0];
1845 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1847 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1849 m.pointer_texcoord3f[1] = vertex3f;
1850 m.texmatrix[1] = *matrix_modeltoattenuationz;
1852 m.pointer_texcoord[1] = varray_texcoord2f[1];
1853 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1856 GL_ColorMask(0,0,0,1);
1857 GL_BlendFunc(GL_ONE, GL_ZERO);
1858 GL_LockArrays(0, numverts);
1859 R_Mesh_Draw(numverts, numtriangles, elements);
1860 GL_LockArrays(0, 0);
1862 c_rt_lighttris += numtriangles;
1864 memset(&m, 0, sizeof(m));
1865 m.pointer_vertex = vertex3f;
1866 m.tex[0] = R_GetTexture(basetexture);
1867 m.pointer_texcoord[0] = texcoord2f;
1870 m.texcubemap[1] = R_GetTexture(lightcubemap);
1872 m.pointer_texcoord3f[1] = vertex3f;
1873 m.texmatrix[1] = *matrix_modeltolight;
1875 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1876 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1879 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1881 // this final code is shared
1883 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1884 VectorScale(lightcolor, colorscale, color2);
1885 GL_LockArrays(0, numverts);
1886 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1888 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1889 R_Mesh_Draw(numverts, numtriangles, elements);
1891 c_rt_lighttris += numtriangles;
1893 GL_LockArrays(0, 0);
1898 colorscale = diffusescale;
1899 // colorscale accounts for how much we multiply the brightness
1902 // mult is how many times the final pass of the lighting will be
1903 // performed to get more brightness than otherwise possible.
1905 // Limit mult to 64 for sanity sake.
1906 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1908 // 3/2 3D combine path (Geforce3, Radeon 8500)
1909 memset(&m, 0, sizeof(m));
1910 m.pointer_vertex = vertex3f;
1911 m.tex[0] = R_GetTexture(bumptexture);
1912 m.texcombinergb[0] = GL_REPLACE;
1913 m.pointer_texcoord[0] = texcoord2f;
1914 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1915 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1916 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1917 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1918 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1920 m.pointer_texcoord3f[2] = vertex3f;
1921 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1923 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1924 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1927 GL_ColorMask(0,0,0,1);
1928 GL_BlendFunc(GL_ONE, GL_ZERO);
1929 GL_LockArrays(0, numverts);
1930 R_Mesh_Draw(numverts, numtriangles, elements);
1931 GL_LockArrays(0, 0);
1933 c_rt_lighttris += numtriangles;
1935 memset(&m, 0, sizeof(m));
1936 m.pointer_vertex = vertex3f;
1937 m.tex[0] = R_GetTexture(basetexture);
1938 m.pointer_texcoord[0] = texcoord2f;
1941 m.texcubemap[1] = R_GetTexture(lightcubemap);
1943 m.pointer_texcoord3f[1] = vertex3f;
1944 m.texmatrix[1] = *matrix_modeltolight;
1946 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1947 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1950 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1952 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1954 // 1/2/2 3D combine path (original Radeon)
1955 memset(&m, 0, sizeof(m));
1956 m.pointer_vertex = vertex3f;
1957 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1959 m.pointer_texcoord3f[0] = vertex3f;
1960 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1962 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1963 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1966 GL_ColorMask(0,0,0,1);
1967 GL_BlendFunc(GL_ONE, GL_ZERO);
1968 GL_LockArrays(0, numverts);
1969 R_Mesh_Draw(numverts, numtriangles, elements);
1970 GL_LockArrays(0, 0);
1972 c_rt_lighttris += numtriangles;
1974 memset(&m, 0, sizeof(m));
1975 m.pointer_vertex = vertex3f;
1976 m.tex[0] = R_GetTexture(bumptexture);
1977 m.texcombinergb[0] = GL_REPLACE;
1978 m.pointer_texcoord[0] = texcoord2f;
1979 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1980 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1981 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1982 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1984 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1985 GL_LockArrays(0, numverts);
1986 R_Mesh_Draw(numverts, numtriangles, elements);
1987 GL_LockArrays(0, 0);
1989 c_rt_lighttris += numtriangles;
1991 memset(&m, 0, sizeof(m));
1992 m.pointer_vertex = vertex3f;
1993 m.tex[0] = R_GetTexture(basetexture);
1994 m.pointer_texcoord[0] = texcoord2f;
1997 m.texcubemap[1] = R_GetTexture(lightcubemap);
1999 m.pointer_texcoord3f[1] = vertex3f;
2000 m.texmatrix[1] = *matrix_modeltolight;
2002 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2003 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2006 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2008 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
2010 // 2/2 3D combine path (original Radeon)
2011 memset(&m, 0, sizeof(m));
2012 m.pointer_vertex = vertex3f;
2013 m.tex[0] = R_GetTexture(bumptexture);
2014 m.texcombinergb[0] = GL_REPLACE;
2015 m.pointer_texcoord[0] = texcoord2f;
2016 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2017 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2018 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2019 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2021 GL_ColorMask(0,0,0,1);
2022 GL_BlendFunc(GL_ONE, GL_ZERO);
2023 GL_LockArrays(0, numverts);
2024 R_Mesh_Draw(numverts, numtriangles, elements);
2025 GL_LockArrays(0, 0);
2027 c_rt_lighttris += numtriangles;
2029 memset(&m, 0, sizeof(m));
2030 m.pointer_vertex = vertex3f;
2031 m.tex[0] = R_GetTexture(basetexture);
2032 m.pointer_texcoord[0] = texcoord2f;
2033 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2035 m.pointer_texcoord3f[1] = vertex3f;
2036 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2038 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2039 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2041 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2043 else if (r_textureunits.integer >= 4)
2045 // 4/2 2D combine path (Geforce3, Radeon 8500)
2046 memset(&m, 0, sizeof(m));
2047 m.pointer_vertex = vertex3f;
2048 m.tex[0] = R_GetTexture(bumptexture);
2049 m.texcombinergb[0] = GL_REPLACE;
2050 m.pointer_texcoord[0] = texcoord2f;
2051 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2052 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2053 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2054 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2055 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2057 m.pointer_texcoord3f[2] = vertex3f;
2058 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2060 m.pointer_texcoord[2] = varray_texcoord2f[2];
2061 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2063 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2065 m.pointer_texcoord3f[3] = vertex3f;
2066 m.texmatrix[3] = *matrix_modeltoattenuationz;
2068 m.pointer_texcoord[3] = varray_texcoord2f[3];
2069 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2072 GL_ColorMask(0,0,0,1);
2073 GL_BlendFunc(GL_ONE, GL_ZERO);
2074 GL_LockArrays(0, numverts);
2075 R_Mesh_Draw(numverts, numtriangles, elements);
2076 GL_LockArrays(0, 0);
2078 c_rt_lighttris += numtriangles;
2080 memset(&m, 0, sizeof(m));
2081 m.pointer_vertex = vertex3f;
2082 m.tex[0] = R_GetTexture(basetexture);
2083 m.pointer_texcoord[0] = texcoord2f;
2086 m.texcubemap[1] = R_GetTexture(lightcubemap);
2088 m.pointer_texcoord3f[1] = vertex3f;
2089 m.texmatrix[1] = *matrix_modeltolight;
2091 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2092 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2095 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2099 // 2/2/2 2D combine path (any dot3 card)
2100 memset(&m, 0, sizeof(m));
2101 m.pointer_vertex = vertex3f;
2102 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2104 m.pointer_texcoord3f[0] = vertex3f;
2105 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2107 m.pointer_texcoord[0] = varray_texcoord2f[0];
2108 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2110 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2112 m.pointer_texcoord3f[1] = vertex3f;
2113 m.texmatrix[1] = *matrix_modeltoattenuationz;
2115 m.pointer_texcoord[1] = varray_texcoord2f[1];
2116 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2119 GL_ColorMask(0,0,0,1);
2120 GL_BlendFunc(GL_ONE, GL_ZERO);
2121 GL_LockArrays(0, numverts);
2122 R_Mesh_Draw(numverts, numtriangles, elements);
2123 GL_LockArrays(0, 0);
2125 c_rt_lighttris += numtriangles;
2127 memset(&m, 0, sizeof(m));
2128 m.pointer_vertex = vertex3f;
2129 m.tex[0] = R_GetTexture(bumptexture);
2130 m.texcombinergb[0] = GL_REPLACE;
2131 m.pointer_texcoord[0] = texcoord2f;
2132 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2133 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2134 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2135 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2137 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2138 GL_LockArrays(0, numverts);
2139 R_Mesh_Draw(numverts, numtriangles, elements);
2140 GL_LockArrays(0, 0);
2142 c_rt_lighttris += numtriangles;
2144 memset(&m, 0, sizeof(m));
2145 m.pointer_vertex = vertex3f;
2146 m.tex[0] = R_GetTexture(basetexture);
2147 m.pointer_texcoord[0] = texcoord2f;
2150 m.texcubemap[1] = R_GetTexture(lightcubemap);
2152 m.pointer_texcoord3f[1] = vertex3f;
2153 m.texmatrix[1] = *matrix_modeltolight;
2155 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2156 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2159 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2161 // this final code is shared
2163 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2164 VectorScale(lightcolor, colorscale, color2);
2165 GL_LockArrays(0, numverts);
2166 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2168 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2169 R_Mesh_Draw(numverts, numtriangles, elements);
2171 c_rt_lighttris += numtriangles;
2173 GL_LockArrays(0, 0);
2175 if (specularscale && glosstexture != r_shadow_blankblacktexture)
2177 // FIXME: detect blendsquare!
2178 //if (gl_support_blendsquare)
2180 colorscale = specularscale;
2182 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2184 // 2/0/0/1/2 3D combine blendsquare path
2185 memset(&m, 0, sizeof(m));
2186 m.pointer_vertex = vertex3f;
2187 m.tex[0] = R_GetTexture(bumptexture);
2188 m.pointer_texcoord[0] = texcoord2f;
2189 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2190 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2191 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2192 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2194 GL_ColorMask(0,0,0,1);
2195 // this squares the result
2196 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2197 GL_LockArrays(0, numverts);
2198 R_Mesh_Draw(numverts, numtriangles, elements);
2199 GL_LockArrays(0, 0);
2201 c_rt_lighttris += numtriangles;
2203 memset(&m, 0, sizeof(m));
2204 m.pointer_vertex = vertex3f;
2206 GL_LockArrays(0, numverts);
2207 // square alpha in framebuffer a few times to make it shiny
2208 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2209 // these comments are a test run through this math for intensity 0.5
2210 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2211 // 0.25 * 0.25 = 0.0625 (this is another pass)
2212 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2213 R_Mesh_Draw(numverts, numtriangles, elements);
2215 c_rt_lighttris += numtriangles;
2216 R_Mesh_Draw(numverts, numtriangles, elements);
2218 c_rt_lighttris += numtriangles;
2219 GL_LockArrays(0, 0);
2221 memset(&m, 0, sizeof(m));
2222 m.pointer_vertex = vertex3f;
2223 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2225 m.pointer_texcoord3f[0] = vertex3f;
2226 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2228 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2229 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2232 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2233 GL_LockArrays(0, numverts);
2234 R_Mesh_Draw(numverts, numtriangles, elements);
2235 GL_LockArrays(0, 0);
2237 c_rt_lighttris += numtriangles;
2239 memset(&m, 0, sizeof(m));
2240 m.pointer_vertex = vertex3f;
2241 m.tex[0] = R_GetTexture(glosstexture);
2242 m.pointer_texcoord[0] = texcoord2f;
2245 m.texcubemap[1] = R_GetTexture(lightcubemap);
2247 m.pointer_texcoord3f[1] = vertex3f;
2248 m.texmatrix[1] = *matrix_modeltolight;
2250 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2251 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2254 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2256 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2258 // 2/0/0/2 3D combine blendsquare path
2259 memset(&m, 0, sizeof(m));
2260 m.pointer_vertex = vertex3f;
2261 m.tex[0] = R_GetTexture(bumptexture);
2262 m.pointer_texcoord[0] = texcoord2f;
2263 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2264 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2265 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2266 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2268 GL_ColorMask(0,0,0,1);
2269 // this squares the result
2270 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2271 GL_LockArrays(0, numverts);
2272 R_Mesh_Draw(numverts, numtriangles, elements);
2273 GL_LockArrays(0, 0);
2275 c_rt_lighttris += numtriangles;
2277 memset(&m, 0, sizeof(m));
2278 m.pointer_vertex = vertex3f;
2280 GL_LockArrays(0, numverts);
2281 // square alpha in framebuffer a few times to make it shiny
2282 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2283 // these comments are a test run through this math for intensity 0.5
2284 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2285 // 0.25 * 0.25 = 0.0625 (this is another pass)
2286 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2287 R_Mesh_Draw(numverts, numtriangles, elements);
2289 c_rt_lighttris += numtriangles;
2290 R_Mesh_Draw(numverts, numtriangles, elements);
2292 c_rt_lighttris += numtriangles;
2293 GL_LockArrays(0, 0);
2295 memset(&m, 0, sizeof(m));
2296 m.pointer_vertex = vertex3f;
2297 m.tex[0] = R_GetTexture(glosstexture);
2298 m.pointer_texcoord[0] = texcoord2f;
2299 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2301 m.pointer_texcoord3f[1] = vertex3f;
2302 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2304 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2305 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2307 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2311 // 2/0/0/2/2 2D combine blendsquare path
2312 memset(&m, 0, sizeof(m));
2313 m.pointer_vertex = vertex3f;
2314 m.tex[0] = R_GetTexture(bumptexture);
2315 m.pointer_texcoord[0] = texcoord2f;
2316 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2317 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2318 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2319 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2321 GL_ColorMask(0,0,0,1);
2322 // this squares the result
2323 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2324 GL_LockArrays(0, numverts);
2325 R_Mesh_Draw(numverts, numtriangles, elements);
2326 GL_LockArrays(0, 0);
2328 c_rt_lighttris += numtriangles;
2330 memset(&m, 0, sizeof(m));
2331 m.pointer_vertex = vertex3f;
2333 GL_LockArrays(0, numverts);
2334 // square alpha in framebuffer a few times to make it shiny
2335 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2336 // these comments are a test run through this math for intensity 0.5
2337 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2338 // 0.25 * 0.25 = 0.0625 (this is another pass)
2339 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2340 R_Mesh_Draw(numverts, numtriangles, elements);
2342 c_rt_lighttris += numtriangles;
2343 R_Mesh_Draw(numverts, numtriangles, elements);
2345 c_rt_lighttris += numtriangles;
2346 GL_LockArrays(0, 0);
2348 memset(&m, 0, sizeof(m));
2349 m.pointer_vertex = vertex3f;
2350 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2352 m.pointer_texcoord3f[0] = vertex3f;
2353 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2355 m.pointer_texcoord[0] = varray_texcoord2f[0];
2356 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2358 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2360 m.pointer_texcoord3f[1] = vertex3f;
2361 m.texmatrix[1] = *matrix_modeltoattenuationz;
2363 m.pointer_texcoord[1] = varray_texcoord2f[1];
2364 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2367 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2368 GL_LockArrays(0, numverts);
2369 R_Mesh_Draw(numverts, numtriangles, elements);
2370 GL_LockArrays(0, 0);
2372 c_rt_lighttris += numtriangles;
2374 memset(&m, 0, sizeof(m));
2375 m.pointer_vertex = vertex3f;
2376 m.tex[0] = R_GetTexture(glosstexture);
2377 m.pointer_texcoord[0] = texcoord2f;
2380 m.texcubemap[1] = R_GetTexture(lightcubemap);
2382 m.pointer_texcoord3f[1] = vertex3f;
2383 m.texmatrix[1] = *matrix_modeltolight;
2385 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2386 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2389 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2392 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2393 VectorScale(lightcolor, colorscale, color2);
2394 GL_LockArrays(0, numverts);
2395 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2397 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2398 R_Mesh_Draw(numverts, numtriangles, elements);
2400 c_rt_lighttris += numtriangles;
2402 GL_LockArrays(0, 0);
2410 GL_BlendFunc(GL_ONE, GL_ONE);
2411 VectorScale(lightcolor, ambientscale, color2);
2412 memset(&m, 0, sizeof(m));
2413 m.pointer_vertex = vertex3f;
2414 m.tex[0] = R_GetTexture(basetexture);
2415 m.pointer_texcoord[0] = texcoord2f;
2416 if (r_textureunits.integer >= 2)
2419 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2421 m.pointer_texcoord3f[1] = vertex3f;
2422 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2424 m.pointer_texcoord[1] = varray_texcoord2f[1];
2425 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2427 if (r_textureunits.integer >= 3)
2429 // Geforce3/Radeon class but not using dot3
2430 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2432 m.pointer_texcoord3f[2] = vertex3f;
2433 m.texmatrix[2] = *matrix_modeltoattenuationz;
2435 m.pointer_texcoord[2] = varray_texcoord2f[2];
2436 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2440 if (r_textureunits.integer >= 3)
2441 m.pointer_color = NULL;
2443 m.pointer_color = varray_color4f;
2445 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2447 color[0] = bound(0, color2[0], 1);
2448 color[1] = bound(0, color2[1], 1);
2449 color[2] = bound(0, color2[2], 1);
2450 if (r_textureunits.integer >= 3)
2451 GL_Color(color[0], color[1], color[2], 1);
2452 else if (r_textureunits.integer >= 2)
2453 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2455 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2456 GL_LockArrays(0, numverts);
2457 R_Mesh_Draw(numverts, numtriangles, elements);
2458 GL_LockArrays(0, 0);
2460 c_rt_lighttris += numtriangles;
2465 GL_BlendFunc(GL_ONE, GL_ONE);
2466 VectorScale(lightcolor, diffusescale, color2);
2467 memset(&m, 0, sizeof(m));
2468 m.pointer_vertex = vertex3f;
2469 m.pointer_color = varray_color4f;
2470 m.tex[0] = R_GetTexture(basetexture);
2471 m.pointer_texcoord[0] = texcoord2f;
2472 if (r_textureunits.integer >= 2)
2475 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2477 m.pointer_texcoord3f[1] = vertex3f;
2478 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2480 m.pointer_texcoord[1] = varray_texcoord2f[1];
2481 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2483 if (r_textureunits.integer >= 3)
2485 // Geforce3/Radeon class but not using dot3
2486 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2488 m.pointer_texcoord3f[2] = vertex3f;
2489 m.texmatrix[2] = *matrix_modeltoattenuationz;
2491 m.pointer_texcoord[2] = varray_texcoord2f[2];
2492 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2497 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2499 color[0] = bound(0, color2[0], 1);
2500 color[1] = bound(0, color2[1], 1);
2501 color[2] = bound(0, color2[2], 1);
2502 if (r_textureunits.integer >= 3)
2503 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2504 else if (r_textureunits.integer >= 2)
2505 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2507 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2508 GL_LockArrays(0, numverts);
2509 R_Mesh_Draw(numverts, numtriangles, elements);
2510 GL_LockArrays(0, 0);
2512 c_rt_lighttris += numtriangles;
2518 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2522 R_RTLight_Uncompile(rtlight);
2523 memset(rtlight, 0, sizeof(*rtlight));
2525 VectorCopy(light->origin, rtlight->shadoworigin);
2526 VectorCopy(light->color, rtlight->color);
2527 rtlight->radius = light->radius;
2528 //rtlight->cullradius = rtlight->radius;
2529 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2530 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2531 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2532 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2533 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2534 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2535 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2536 rtlight->cubemapname[0] = 0;
2537 if (light->cubemapname[0])
2538 strcpy(rtlight->cubemapname, light->cubemapname);
2539 else if (light->cubemapnum > 0)
2540 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2541 rtlight->shadow = light->shadow;
2542 rtlight->corona = light->corona;
2543 rtlight->style = light->style;
2544 rtlight->isstatic = isstatic;
2545 rtlight->coronasizescale = light->coronasizescale;
2546 rtlight->ambientscale = light->ambientscale;
2547 rtlight->diffusescale = light->diffusescale;
2548 rtlight->specularscale = light->specularscale;
2549 rtlight->flags = light->flags;
2550 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2551 // ConcatScale won't work here because this needs to scale rotate and
2552 // translate, not just rotate
2553 scale = 1.0f / rtlight->radius;
2554 for (k = 0;k < 3;k++)
2555 for (j = 0;j < 4;j++)
2556 rtlight->matrix_worldtolight.m[k][j] *= scale;
2557 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2558 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2560 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2561 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2562 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2563 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2566 // compiles rtlight geometry
2567 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2568 void R_RTLight_Compile(rtlight_t *rtlight)
2570 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2571 entity_render_t *ent = &cl_entities[0].render;
2572 model_t *model = ent->model;
2574 // compile the light
2575 rtlight->compiled = true;
2576 rtlight->static_numclusters = 0;
2577 rtlight->static_numclusterpvsbytes = 0;
2578 rtlight->static_clusterlist = NULL;
2579 rtlight->static_clusterpvs = NULL;
2580 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2581 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2582 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2583 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2584 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2585 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2587 if (model && model->GetLightInfo)
2589 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2590 r_shadow_compilingrtlight = rtlight;
2591 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2592 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2593 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);
2594 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2595 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2598 rtlight->static_numclusters = numclusters;
2599 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2600 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2601 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2603 if (model->DrawShadowVolume && rtlight->shadow)
2605 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2606 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2607 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2609 if (model->DrawLight)
2611 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2612 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);
2613 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2615 // switch back to rendering when DrawShadowVolume or DrawLight is called
2616 r_shadow_compilingrtlight = NULL;
2620 // use smallest available cullradius - box radius or light radius
2621 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2622 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2626 if (rtlight->static_meshchain_shadow)
2629 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2632 shadowtris += mesh->numtriangles;
2638 if (rtlight->static_meshchain_light)
2641 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2644 lighttris += mesh->numtriangles;
2648 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);
2651 void R_RTLight_Uncompile(rtlight_t *rtlight)
2653 if (rtlight->compiled)
2655 if (rtlight->static_meshchain_shadow)
2656 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2657 rtlight->static_meshchain_shadow = NULL;
2658 if (rtlight->static_meshchain_light)
2659 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2660 rtlight->static_meshchain_light = NULL;
2661 if (rtlight->static_clusterlist)
2662 Mem_Free(rtlight->static_clusterlist);
2663 rtlight->static_clusterlist = NULL;
2664 if (rtlight->static_clusterpvs)
2665 Mem_Free(rtlight->static_clusterpvs);
2666 rtlight->static_clusterpvs = NULL;
2667 rtlight->static_numclusters = 0;
2668 rtlight->static_numclusterpvsbytes = 0;
2669 rtlight->compiled = false;
2673 void R_Shadow_UncompileWorldLights(void)
2676 for (light = r_shadow_worldlightchain;light;light = light->next)
2677 R_RTLight_Uncompile(&light->rtlight);
2680 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2682 int i, shadow, usestencil;
2683 entity_render_t *ent;
2685 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2686 rtexture_t *cubemaptexture;
2687 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2688 int numclusters, numsurfaces;
2689 int *clusterlist, *surfacelist;
2691 vec3_t cullmins, cullmaxs;
2695 // skip lights that don't light (corona only lights)
2696 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2699 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2700 VectorScale(rtlight->color, f, lightcolor);
2701 if (VectorLength2(lightcolor) < 0.01)
2704 if (rtlight->selected)
2706 f = 2 + sin(realtime * M_PI * 4.0);
2707 VectorScale(lightcolor, f, lightcolor);
2711 // loading is done before visibility checks because loading should happen
2712 // all at once at the start of a level, not when it stalls gameplay.
2713 // (especially important to benchmarks)
2714 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2715 R_RTLight_Compile(rtlight);
2716 if (rtlight->cubemapname[0])
2717 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2719 cubemaptexture = NULL;
2721 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2722 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2723 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2724 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2725 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2726 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2727 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2734 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2736 // compiled light, world available and can receive realtime lighting
2737 // retrieve cluster information
2738 numclusters = rtlight->static_numclusters;
2739 clusterlist = rtlight->static_clusterlist;
2740 clusterpvs = rtlight->static_clusterpvs;
2741 VectorCopy(rtlight->cullmins, cullmins);
2742 VectorCopy(rtlight->cullmaxs, cullmaxs);
2744 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2746 // dynamic light, world available and can receive realtime lighting
2747 // if the light box is offscreen, skip it right away
2748 if (R_CullBox(cullmins, cullmaxs))
2750 // calculate lit surfaces and clusters
2751 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2752 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2753 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);
2754 clusterlist = r_shadow_buffer_clusterlist;
2755 clusterpvs = r_shadow_buffer_clusterpvs;
2756 surfacelist = r_shadow_buffer_surfacelist;
2758 // if the reduced cluster bounds are offscreen, skip it
2759 if (R_CullBox(cullmins, cullmaxs))
2761 // check if light is illuminating any visible clusters
2764 for (i = 0;i < numclusters;i++)
2765 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2767 if (i == numclusters)
2770 // set up a scissor rectangle for this light
2771 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2774 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2777 if (shadow && (gl_stencil || visiblevolumes))
2779 if (!visiblevolumes)
2781 R_Shadow_Stage_ShadowVolumes();
2784 ent = &cl_entities[0].render;
2785 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2787 memset(&m, 0, sizeof(m));
2788 R_Mesh_Matrix(&ent->matrix);
2789 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2791 m.pointer_vertex = mesh->vertex3f;
2793 GL_LockArrays(0, mesh->numverts);
2794 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2796 // increment stencil if backface is behind depthbuffer
2797 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2798 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2799 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2800 c_rtcached_shadowmeshes++;
2801 c_rtcached_shadowtris += mesh->numtriangles;
2802 // decrement stencil if frontface is behind depthbuffer
2803 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2804 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2806 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2807 c_rtcached_shadowmeshes++;
2808 c_rtcached_shadowtris += mesh->numtriangles;
2809 GL_LockArrays(0, 0);
2812 else if (numsurfaces)
2814 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2815 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2817 if (r_drawentities.integer)
2819 for (i = 0;i < r_refdef.numentities;i++)
2821 ent = r_refdef.entities[i];
2823 if (r_shadow_cull.integer)
2825 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2827 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2830 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2832 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2833 // light emitting entities should not cast their own shadow
2834 if (VectorLength2(relativelightorigin) < 0.1)
2836 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2841 if (!visiblevolumes)
2843 R_Shadow_Stage_Light(usestencil);
2845 ent = &cl_entities[0].render;
2846 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2848 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2849 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2850 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2851 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2852 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2853 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2854 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2855 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2856 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2858 R_Mesh_Matrix(&ent->matrix);
2859 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2860 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);
2863 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2865 if (r_drawentities.integer)
2867 for (i = 0;i < r_refdef.numentities;i++)
2869 ent = r_refdef.entities[i];
2870 // can't draw transparent entity lighting here because
2871 // transparent meshes are deferred for later
2872 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)
2874 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2875 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2876 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2877 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2878 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2879 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2880 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2881 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2882 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);
2889 void R_ShadowVolumeLighting(int visiblevolumes)
2895 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2896 R_Shadow_EditLights_Reload_f();
2900 memset(&m, 0, sizeof(m));
2903 GL_BlendFunc(GL_ONE, GL_ONE);
2904 GL_DepthMask(false);
2905 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2906 qglDisable(GL_CULL_FACE);
2907 GL_Color(0.0, 0.0125, 0.1, 1);
2910 R_Shadow_Stage_Begin();
2911 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2912 if (r_shadow_debuglight.integer >= 0)
2914 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2915 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2916 R_DrawRTLight(&light->rtlight, visiblevolumes);
2919 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2920 if (light->flags & flag)
2921 R_DrawRTLight(&light->rtlight, visiblevolumes);
2923 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2924 R_DrawRTLight(&light->rtlight, visiblevolumes);
2928 qglEnable(GL_CULL_FACE);
2929 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2932 R_Shadow_Stage_End();
2935 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2936 typedef struct suffixinfo_s
2939 qboolean flipx, flipy, flipdiagonal;
2942 static suffixinfo_t suffix[3][6] =
2945 {"px", false, false, false},
2946 {"nx", false, false, false},
2947 {"py", false, false, false},
2948 {"ny", false, false, false},
2949 {"pz", false, false, false},
2950 {"nz", false, false, false}
2953 {"posx", false, false, false},
2954 {"negx", false, false, false},
2955 {"posy", false, false, false},
2956 {"negy", false, false, false},
2957 {"posz", false, false, false},
2958 {"negz", false, false, false}
2961 {"rt", true, false, true},
2962 {"lf", false, true, true},
2963 {"ft", true, true, false},
2964 {"bk", false, false, false},
2965 {"up", true, false, true},
2966 {"dn", true, false, true}
2970 static int componentorder[4] = {0, 1, 2, 3};
2972 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2974 int i, j, cubemapsize;
2975 qbyte *cubemappixels, *image_rgba;
2976 rtexture_t *cubemaptexture;
2978 // must start 0 so the first loadimagepixels has no requested width/height
2980 cubemappixels = NULL;
2981 cubemaptexture = NULL;
2982 // keep trying different suffix groups (posx, px, rt) until one loads
2983 for (j = 0;j < 3 && !cubemappixels;j++)
2985 // load the 6 images in the suffix group
2986 for (i = 0;i < 6;i++)
2988 // generate an image name based on the base and and suffix
2989 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2991 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2993 // an image loaded, make sure width and height are equal
2994 if (image_width == image_height)
2996 // if this is the first image to load successfully, allocate the cubemap memory
2997 if (!cubemappixels && image_width >= 1)
2999 cubemapsize = image_width;
3000 // note this clears to black, so unavailable sides are black
3001 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3003 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3005 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);
3008 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3010 Mem_Free(image_rgba);
3014 // if a cubemap loaded, upload it
3017 if (!r_shadow_filters_texturepool)
3018 r_shadow_filters_texturepool = R_AllocTexturePool();
3019 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3020 Mem_Free(cubemappixels);
3024 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3025 for (j = 0;j < 3;j++)
3026 for (i = 0;i < 6;i++)
3027 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3028 Con_Print(" and was unable to find any of them.\n");
3030 return cubemaptexture;
3033 rtexture_t *R_Shadow_Cubemap(const char *basename)
3036 for (i = 0;i < numcubemaps;i++)
3037 if (!strcasecmp(cubemaps[i].basename, basename))
3038 return cubemaps[i].texture;
3039 if (i >= MAX_CUBEMAPS)
3042 strcpy(cubemaps[i].basename, basename);
3043 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3044 return cubemaps[i].texture;
3047 void R_Shadow_FreeCubemaps(void)
3050 R_FreeTexturePool(&r_shadow_filters_texturepool);
3053 dlight_t *R_Shadow_NewWorldLight(void)
3056 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3057 light->next = r_shadow_worldlightchain;
3058 r_shadow_worldlightchain = light;
3062 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)
3064 VectorCopy(origin, light->origin);
3065 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3066 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3067 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3068 light->color[0] = max(color[0], 0);
3069 light->color[1] = max(color[1], 0);
3070 light->color[2] = max(color[2], 0);
3071 light->radius = max(radius, 0);
3072 light->style = style;
3073 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3075 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3078 light->shadow = shadowenable;
3079 light->corona = corona;
3082 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
3083 light->coronasizescale = coronasizescale;
3084 light->ambientscale = ambientscale;
3085 light->diffusescale = diffusescale;
3086 light->specularscale = specularscale;
3087 light->flags = flags;
3088 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3090 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3093 void R_Shadow_FreeWorldLight(dlight_t *light)
3095 dlight_t **lightpointer;
3096 R_RTLight_Uncompile(&light->rtlight);
3097 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3098 if (*lightpointer != light)
3099 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3100 *lightpointer = light->next;
3104 void R_Shadow_ClearWorldLights(void)
3106 while (r_shadow_worldlightchain)
3107 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3108 r_shadow_selectedlight = NULL;
3109 R_Shadow_FreeCubemaps();
3112 void R_Shadow_SelectLight(dlight_t *light)
3114 if (r_shadow_selectedlight)
3115 r_shadow_selectedlight->selected = false;
3116 r_shadow_selectedlight = light;
3117 if (r_shadow_selectedlight)
3118 r_shadow_selectedlight->selected = true;
3121 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3123 float scale = r_editlights_cursorgrid.value * 0.5f;
3124 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);
3127 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3130 const dlight_t *light;
3133 if (light->selected)
3134 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3137 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);
3140 void R_Shadow_DrawLightSprites(void)
3146 for (i = 0;i < 5;i++)
3148 lighttextures[i] = NULL;
3149 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3150 lighttextures[i] = pic->tex;
3153 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3154 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3155 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3158 void R_Shadow_SelectLightInView(void)
3160 float bestrating, rating, temp[3];
3161 dlight_t *best, *light;
3164 for (light = r_shadow_worldlightchain;light;light = light->next)
3166 VectorSubtract(light->origin, r_vieworigin, temp);
3167 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3170 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3171 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3173 bestrating = rating;
3178 R_Shadow_SelectLight(best);
3181 void R_Shadow_LoadWorldLights(void)
3183 int n, a, style, shadow, flags;
3184 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3185 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3186 if (r_refdef.worldmodel == NULL)
3188 Con_Print("No map loaded.\n");
3191 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3192 strlcat (name, ".rtlights", sizeof (name));
3193 lightsstring = FS_LoadFile(name, tempmempool, false);
3203 for (;COM_Parse(t, true) && strcmp(
3204 if (COM_Parse(t, true))
3206 if (com_token[0] == '!')
3209 origin[0] = atof(com_token+1);
3212 origin[0] = atof(com_token);
3217 while (*s && *s != '\n' && *s != '\r')
3223 // check for modifier flags
3230 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);
3233 flags = LIGHTFLAG_REALTIMEMODE;
3241 coronasizescale = 0.25f;
3243 VectorClear(angles);
3246 if (a < 9 || !strcmp(cubemapname, "\"\""))
3248 // remove quotes on cubemapname
3249 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3251 cubemapname[strlen(cubemapname)-1] = 0;
3252 strcpy(cubemapname, cubemapname + 1);
3256 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);
3259 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3260 radius *= r_editlights_rtlightssizescale.value;
3261 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3269 Con_Printf("invalid rtlights file \"%s\"\n", name);
3270 Mem_Free(lightsstring);
3274 void R_Shadow_SaveWorldLights(void)
3277 int bufchars, bufmaxchars;
3279 char name[MAX_QPATH];
3281 if (!r_shadow_worldlightchain)
3283 if (r_refdef.worldmodel == NULL)
3285 Con_Print("No map loaded.\n");
3288 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3289 strlcat (name, ".rtlights", sizeof (name));
3290 bufchars = bufmaxchars = 0;
3292 for (light = r_shadow_worldlightchain;light;light = light->next)
3294 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3295 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);
3296 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3297 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]);
3299 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);
3300 if (bufchars + (int) strlen(line) > bufmaxchars)
3302 bufmaxchars = bufchars + strlen(line) + 2048;
3304 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3308 memcpy(buf, oldbuf, bufchars);
3314 memcpy(buf + bufchars, line, strlen(line));
3315 bufchars += strlen(line);
3319 FS_WriteFile(name, buf, bufchars);
3324 void R_Shadow_LoadLightsFile(void)
3327 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3328 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3329 if (r_refdef.worldmodel == NULL)
3331 Con_Print("No map loaded.\n");
3334 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3335 strlcat (name, ".lights", sizeof (name));
3336 lightsstring = FS_LoadFile(name, tempmempool, false);
3344 while (*s && *s != '\n' && *s != '\r')
3350 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);
3354 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);
3357 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3358 radius = bound(15, radius, 4096);
3359 VectorScale(color, (2.0f / (8388608.0f)), color);
3360 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3368 Con_Printf("invalid lights file \"%s\"\n", name);
3369 Mem_Free(lightsstring);
3373 // tyrlite/hmap2 light types in the delay field
3374 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3376 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3378 int entnum, style, islight, skin, pflags, effects, type, n;
3381 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3382 char key[256], value[1024];
3384 if (r_refdef.worldmodel == NULL)
3386 Con_Print("No map loaded.\n");
3389 // try to load a .ent file first
3390 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3391 strlcat (key, ".ent", sizeof (key));
3392 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3393 // and if that is not found, fall back to the bsp file entity string
3395 data = r_refdef.worldmodel->brush.entities;
3398 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3400 type = LIGHTTYPE_MINUSX;
3401 origin[0] = origin[1] = origin[2] = 0;
3402 originhack[0] = originhack[1] = originhack[2] = 0;
3403 angles[0] = angles[1] = angles[2] = 0;
3404 color[0] = color[1] = color[2] = 1;
3405 light[0] = light[1] = light[2] = 1;light[3] = 300;
3406 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3416 if (!COM_ParseToken(&data, false))
3418 if (com_token[0] == '}')
3419 break; // end of entity
3420 if (com_token[0] == '_')
3421 strcpy(key, com_token + 1);
3423 strcpy(key, com_token);
3424 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3425 key[strlen(key)-1] = 0;
3426 if (!COM_ParseToken(&data, false))
3428 strcpy(value, com_token);
3430 // now that we have the key pair worked out...
3431 if (!strcmp("light", key))
3433 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3437 light[0] = vec[0] * (1.0f / 256.0f);
3438 light[1] = vec[0] * (1.0f / 256.0f);
3439 light[2] = vec[0] * (1.0f / 256.0f);
3445 light[0] = vec[0] * (1.0f / 255.0f);
3446 light[1] = vec[1] * (1.0f / 255.0f);
3447 light[2] = vec[2] * (1.0f / 255.0f);
3451 else if (!strcmp("delay", key))
3453 else if (!strcmp("origin", key))
3454 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3455 else if (!strcmp("angle", key))
3456 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3457 else if (!strcmp("angles", key))
3458 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3459 else if (!strcmp("color", key))
3460 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3461 else if (!strcmp("wait", key))
3462 fadescale = atof(value);
3463 else if (!strcmp("classname", key))
3465 if (!strncmp(value, "light", 5))
3468 if (!strcmp(value, "light_fluoro"))
3473 overridecolor[0] = 1;
3474 overridecolor[1] = 1;
3475 overridecolor[2] = 1;
3477 if (!strcmp(value, "light_fluorospark"))
3482 overridecolor[0] = 1;
3483 overridecolor[1] = 1;
3484 overridecolor[2] = 1;
3486 if (!strcmp(value, "light_globe"))
3491 overridecolor[0] = 1;
3492 overridecolor[1] = 0.8;
3493 overridecolor[2] = 0.4;
3495 if (!strcmp(value, "light_flame_large_yellow"))
3500 overridecolor[0] = 1;
3501 overridecolor[1] = 0.5;
3502 overridecolor[2] = 0.1;
3504 if (!strcmp(value, "light_flame_small_yellow"))
3509 overridecolor[0] = 1;
3510 overridecolor[1] = 0.5;
3511 overridecolor[2] = 0.1;
3513 if (!strcmp(value, "light_torch_small_white"))
3518 overridecolor[0] = 1;
3519 overridecolor[1] = 0.5;
3520 overridecolor[2] = 0.1;
3522 if (!strcmp(value, "light_torch_small_walltorch"))
3527 overridecolor[0] = 1;
3528 overridecolor[1] = 0.5;
3529 overridecolor[2] = 0.1;
3533 else if (!strcmp("style", key))
3534 style = atoi(value);
3535 else if (r_refdef.worldmodel->type == mod_brushq3)
3537 if (!strcmp("scale", key))
3538 lightscale = atof(value);
3539 if (!strcmp("fade", key))
3540 fadescale = atof(value);
3542 else if (!strcmp("skin", key))
3543 skin = (int)atof(value);
3544 else if (!strcmp("pflags", key))
3545 pflags = (int)atof(value);
3546 else if (!strcmp("effects", key))
3547 effects = (int)atof(value);
3551 if (lightscale <= 0)
3555 if (color[0] == color[1] && color[0] == color[2])
3557 color[0] *= overridecolor[0];
3558 color[1] *= overridecolor[1];
3559 color[2] *= overridecolor[2];
3561 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3562 color[0] = color[0] * light[0];
3563 color[1] = color[1] * light[1];
3564 color[2] = color[2] * light[2];
3567 case LIGHTTYPE_MINUSX:
3569 case LIGHTTYPE_RECIPX:
3571 VectorScale(color, (1.0f / 16.0f), color);
3573 case LIGHTTYPE_RECIPXX:
3575 VectorScale(color, (1.0f / 16.0f), color);
3578 case LIGHTTYPE_NONE:
3582 case LIGHTTYPE_MINUSXX:
3585 VectorAdd(origin, originhack, origin);
3587 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);
3590 Mem_Free(entfiledata);
3594 void R_Shadow_SetCursorLocationForView(void)
3596 vec_t dist, push, frac;
3597 vec3_t dest, endpos, normal;
3598 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3599 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3602 dist = frac * r_editlights_cursordistance.value;
3603 push = r_editlights_cursorpushback.value;
3607 VectorMA(endpos, push, r_viewforward, endpos);
3608 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3610 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3611 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3612 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3615 void R_Shadow_UpdateWorldLightSelection(void)
3617 if (r_editlights.integer)
3619 R_Shadow_SetCursorLocationForView();
3620 R_Shadow_SelectLightInView();
3621 R_Shadow_DrawLightSprites();
3624 R_Shadow_SelectLight(NULL);
3627 void R_Shadow_EditLights_Clear_f(void)
3629 R_Shadow_ClearWorldLights();
3632 void R_Shadow_EditLights_Reload_f(void)
3634 if (!r_refdef.worldmodel)
3636 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3637 R_Shadow_ClearWorldLights();
3638 R_Shadow_LoadWorldLights();
3639 if (r_shadow_worldlightchain == NULL)
3641 R_Shadow_LoadLightsFile();
3642 if (r_shadow_worldlightchain == NULL)
3643 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3647 void R_Shadow_EditLights_Save_f(void)
3649 if (!r_refdef.worldmodel)
3651 R_Shadow_SaveWorldLights();
3654 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3656 R_Shadow_ClearWorldLights();
3657 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3660 void R_Shadow_EditLights_ImportLightsFile_f(void)
3662 R_Shadow_ClearWorldLights();
3663 R_Shadow_LoadLightsFile();
3666 void R_Shadow_EditLights_Spawn_f(void)
3669 if (!r_editlights.integer)
3671 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3674 if (Cmd_Argc() != 1)
3676 Con_Print("r_editlights_spawn does not take parameters\n");
3679 color[0] = color[1] = color[2] = 1;
3680 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3683 void R_Shadow_EditLights_Edit_f(void)
3685 vec3_t origin, angles, color;
3686 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3687 int style, shadows, flags, normalmode, realtimemode;
3688 char cubemapname[1024];
3689 if (!r_editlights.integer)
3691 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3694 if (!r_shadow_selectedlight)
3696 Con_Print("No selected light.\n");
3699 VectorCopy(r_shadow_selectedlight->origin, origin);
3700 VectorCopy(r_shadow_selectedlight->angles, angles);
3701 VectorCopy(r_shadow_selectedlight->color, color);
3702 radius = r_shadow_selectedlight->radius;
3703 style = r_shadow_selectedlight->style;
3704 if (r_shadow_selectedlight->cubemapname)
3705 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3708 shadows = r_shadow_selectedlight->shadow;
3709 corona = r_shadow_selectedlight->corona;
3710 coronasizescale = r_shadow_selectedlight->coronasizescale;
3711 ambientscale = r_shadow_selectedlight->ambientscale;
3712 diffusescale = r_shadow_selectedlight->diffusescale;
3713 specularscale = r_shadow_selectedlight->specularscale;
3714 flags = r_shadow_selectedlight->flags;
3715 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3716 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3717 if (!strcmp(Cmd_Argv(1), "origin"))
3719 if (Cmd_Argc() != 5)
3721 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3724 origin[0] = atof(Cmd_Argv(2));
3725 origin[1] = atof(Cmd_Argv(3));
3726 origin[2] = atof(Cmd_Argv(4));
3728 else if (!strcmp(Cmd_Argv(1), "originx"))
3730 if (Cmd_Argc() != 3)
3732 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3735 origin[0] = atof(Cmd_Argv(2));
3737 else if (!strcmp(Cmd_Argv(1), "originy"))
3739 if (Cmd_Argc() != 3)
3741 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3744 origin[1] = atof(Cmd_Argv(2));
3746 else if (!strcmp(Cmd_Argv(1), "originz"))
3748 if (Cmd_Argc() != 3)
3750 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3753 origin[2] = atof(Cmd_Argv(2));
3755 else if (!strcmp(Cmd_Argv(1), "move"))
3757 if (Cmd_Argc() != 5)
3759 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3762 origin[0] += atof(Cmd_Argv(2));
3763 origin[1] += atof(Cmd_Argv(3));
3764 origin[2] += atof(Cmd_Argv(4));
3766 else if (!strcmp(Cmd_Argv(1), "movex"))
3768 if (Cmd_Argc() != 3)
3770 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3773 origin[0] += atof(Cmd_Argv(2));
3775 else if (!strcmp(Cmd_Argv(1), "movey"))
3777 if (Cmd_Argc() != 3)
3779 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3782 origin[1] += atof(Cmd_Argv(2));
3784 else if (!strcmp(Cmd_Argv(1), "movez"))
3786 if (Cmd_Argc() != 3)
3788 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3791 origin[2] += atof(Cmd_Argv(2));
3793 else if (!strcmp(Cmd_Argv(1), "angles"))
3795 if (Cmd_Argc() != 5)
3797 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3800 angles[0] = atof(Cmd_Argv(2));
3801 angles[1] = atof(Cmd_Argv(3));
3802 angles[2] = atof(Cmd_Argv(4));
3804 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3806 if (Cmd_Argc() != 3)
3808 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3811 angles[0] = atof(Cmd_Argv(2));
3813 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3815 if (Cmd_Argc() != 3)
3817 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3820 angles[1] = atof(Cmd_Argv(2));
3822 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3824 if (Cmd_Argc() != 3)
3826 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3829 angles[2] = atof(Cmd_Argv(2));
3831 else if (!strcmp(Cmd_Argv(1), "color"))
3833 if (Cmd_Argc() != 5)
3835 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3838 color[0] = atof(Cmd_Argv(2));
3839 color[1] = atof(Cmd_Argv(3));
3840 color[2] = atof(Cmd_Argv(4));
3842 else if (!strcmp(Cmd_Argv(1), "radius"))
3844 if (Cmd_Argc() != 3)
3846 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3849 radius = atof(Cmd_Argv(2));
3851 else if (!strcmp(Cmd_Argv(1), "style"))
3853 if (Cmd_Argc() != 3)
3855 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3858 style = atoi(Cmd_Argv(2));
3860 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3864 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3867 if (Cmd_Argc() == 3)
3868 strcpy(cubemapname, Cmd_Argv(2));
3872 else if (!strcmp(Cmd_Argv(1), "shadows"))
3874 if (Cmd_Argc() != 3)
3876 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3879 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3881 else if (!strcmp(Cmd_Argv(1), "corona"))
3883 if (Cmd_Argc() != 3)
3885 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3888 corona = atof(Cmd_Argv(2));
3890 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3892 if (Cmd_Argc() != 3)
3894 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3897 coronasizescale = atof(Cmd_Argv(2));
3899 else if (!strcmp(Cmd_Argv(1), "ambient"))
3901 if (Cmd_Argc() != 3)
3903 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3906 ambientscale = atof(Cmd_Argv(2));
3908 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3910 if (Cmd_Argc() != 3)
3912 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3915 diffusescale = atof(Cmd_Argv(2));
3917 else if (!strcmp(Cmd_Argv(1), "specular"))
3919 if (Cmd_Argc() != 3)
3921 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3924 specularscale = atof(Cmd_Argv(2));
3926 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3928 if (Cmd_Argc() != 3)
3930 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3933 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3935 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3937 if (Cmd_Argc() != 3)
3939 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3942 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3946 Con_Print("usage: r_editlights_edit [property] [value]\n");
3947 Con_Print("Selected light's properties:\n");
3948 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3949 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3950 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3951 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3952 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3953 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3954 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3955 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3956 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3957 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3958 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3959 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3960 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3961 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3964 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3965 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3968 void R_Shadow_EditLights_EditAll_f(void)
3972 if (!r_editlights.integer)
3974 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3978 for (light = r_shadow_worldlightchain;light;light = light->next)
3980 R_Shadow_SelectLight(light);
3981 R_Shadow_EditLights_Edit_f();
3985 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3987 int lightnumber, lightcount;
3991 if (!r_editlights.integer)
3997 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3998 if (light == r_shadow_selectedlight)
3999 lightnumber = lightcount;
4000 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;
4001 if (r_shadow_selectedlight == NULL)
4003 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4004 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;
4005 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;
4006 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;
4007 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4008 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4009 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4010 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;
4011 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4012 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4013 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4014 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4015 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4016 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;
4017 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;
4020 void R_Shadow_EditLights_ToggleShadow_f(void)
4022 if (!r_editlights.integer)
4024 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4027 if (!r_shadow_selectedlight)
4029 Con_Print("No selected light.\n");
4032 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);
4035 void R_Shadow_EditLights_ToggleCorona_f(void)
4037 if (!r_editlights.integer)
4039 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4042 if (!r_shadow_selectedlight)
4044 Con_Print("No selected light.\n");
4047 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);
4050 void R_Shadow_EditLights_Remove_f(void)
4052 if (!r_editlights.integer)
4054 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4057 if (!r_shadow_selectedlight)
4059 Con_Print("No selected light.\n");
4062 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4063 r_shadow_selectedlight = NULL;
4066 void R_Shadow_EditLights_Help_f(void)
4069 "Documentation on r_editlights system:\n"
4071 "r_editlights : enable/disable editing mode\n"
4072 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4073 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4074 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4075 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4076 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4077 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4078 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4080 "r_editlights_help : this help\n"
4081 "r_editlights_clear : remove all lights\n"
4082 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4083 "r_editlights_save : save to .rtlights file\n"
4084 "r_editlights_spawn : create a light with default settings\n"
4085 "r_editlights_edit command : edit selected light - more documentation below\n"
4086 "r_editlights_remove : remove selected light\n"
4087 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4088 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4089 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4091 "origin x y z : set light location\n"
4092 "originx x: set x component of light location\n"
4093 "originy y: set y component of light location\n"
4094 "originz z: set z component of light location\n"
4095 "move x y z : adjust light location\n"
4096 "movex x: adjust x component of light location\n"
4097 "movey y: adjust y component of light location\n"
4098 "movez z: adjust z component of light location\n"
4099 "angles x y z : set light angles\n"
4100 "anglesx x: set x component of light angles\n"
4101 "anglesy y: set y component of light angles\n"
4102 "anglesz z: set z component of light angles\n"
4103 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4104 "radius radius : set radius (size) of light\n"
4105 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4106 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4107 "shadows 1/0 : turn on/off shadows\n"
4108 "corona n : set corona intensity\n"
4109 "coronasize n : set corona size (0-1)\n"
4110 "ambient n : set ambient intensity (0-1)\n"
4111 "diffuse n : set diffuse intensity (0-1)\n"
4112 "specular n : set specular intensity (0-1)\n"
4113 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4114 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4115 "<nothing> : print light properties to console\n"
4119 void R_Shadow_EditLights_CopyInfo_f(void)
4121 if (!r_editlights.integer)
4123 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4126 if (!r_shadow_selectedlight)
4128 Con_Print("No selected light.\n");
4131 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4132 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4133 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4134 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4135 if (r_shadow_selectedlight->cubemapname)
4136 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4138 r_shadow_bufferlight.cubemapname[0] = 0;
4139 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4140 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4141 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4142 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4143 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4144 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4145 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4148 void R_Shadow_EditLights_PasteInfo_f(void)
4150 if (!r_editlights.integer)
4152 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4155 if (!r_shadow_selectedlight)
4157 Con_Print("No selected light.\n");
4160 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);
4163 void R_Shadow_EditLights_Init(void)
4165 Cvar_RegisterVariable(&r_editlights);
4166 Cvar_RegisterVariable(&r_editlights_cursordistance);
4167 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4168 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4169 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4170 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4171 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4172 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4173 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4174 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4175 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4176 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4177 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4178 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4179 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4180 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4181 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4182 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4183 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4184 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4185 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4186 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);