3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankwhitecubetexture;
159 // lights are reloaded when this changes
160 char r_shadow_mapname[MAX_QPATH];
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
165 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
166 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
167 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
168 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
169 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
170 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
171 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
172 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
173 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
174 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
175 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
176 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
177 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
178 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
179 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
180 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
181 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
182 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
183 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
184 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
185 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
186 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
187 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
188 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
189 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
192 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
193 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
194 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
195 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
196 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
197 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
198 cvar_t r_editlights = {0, "r_editlights", "0"};
199 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
200 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
201 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
202 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
203 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
204 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
205 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
207 float r_shadow_attenpower, r_shadow_attenscale;
209 rtlight_t *r_shadow_compilingrtlight;
210 dlight_t *r_shadow_worldlightchain;
211 dlight_t *r_shadow_selectedlight;
212 dlight_t r_shadow_bufferlight;
213 vec3_t r_editlights_cursorlocation;
215 rtexture_t *lighttextures[5];
217 extern int con_vislines;
219 typedef struct cubemapinfo_s
226 #define MAX_CUBEMAPS 256
227 static int numcubemaps;
228 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
230 #define SHADERPERMUTATION_SPECULAR (1<<0)
231 #define SHADERPERMUTATION_FOG (1<<1)
232 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
233 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
234 #define SHADERPERMUTATION_COUNT (1<<4)
236 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
238 void R_Shadow_UncompileWorldLights(void);
239 void R_Shadow_ClearWorldLights(void);
240 void R_Shadow_SaveWorldLights(void);
241 void R_Shadow_LoadWorldLights(void);
242 void R_Shadow_LoadLightsFile(void);
243 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
244 void R_Shadow_EditLights_Reload_f(void);
245 void R_Shadow_ValidateCvars(void);
246 static void R_Shadow_MakeTextures(void);
247 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
249 const char *builtinshader_light_vert =
250 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
251 "// written by Forest 'LordHavoc' Hale\n"
253 "uniform vec3 LightPosition;\n"
255 "varying vec2 TexCoord;\n"
256 "varying vec3 CubeVector;\n"
257 "varying vec3 LightVector;\n"
259 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
260 "uniform vec3 EyePosition;\n"
261 "varying vec3 EyeVector;\n"
264 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
268 " // copy the surface texcoord\n"
269 " TexCoord = gl_MultiTexCoord0.st;\n"
271 " // transform vertex position into light attenuation/cubemap space\n"
272 " // (-1 to +1 across the light box)\n"
273 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
275 " // transform unnormalized light direction into tangent space\n"
276 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
277 " // normalize it per pixel)\n"
278 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
279 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
280 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
281 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
283 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
284 " // transform unnormalized eye direction into tangent space\n"
285 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
286 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
287 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
288 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
291 " // transform vertex to camera space, using ftransform to match non-VS\n"
293 " gl_Position = ftransform();\n"
297 const char *builtinshader_light_frag =
298 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
299 "// written by Forest 'LordHavoc' Hale\n"
301 "uniform vec3 LightColor;\n"
303 "#ifdef USEOFFSETMAPPING\n"
304 "uniform float OffsetMapping_Scale;\n"
305 "uniform float OffsetMapping_Bias;\n"
307 "#ifdef USESPECULAR\n"
308 "uniform float SpecularPower;\n"
311 "uniform float FogRangeRecip;\n"
313 "uniform float AmbientScale;\n"
314 "uniform float DiffuseScale;\n"
315 "#ifdef USESPECULAR\n"
316 "uniform float SpecularScale;\n"
319 "uniform sampler2D Texture_Normal;\n"
320 "uniform sampler2D Texture_Color;\n"
321 "#ifdef USESPECULAR\n"
322 "uniform sampler2D Texture_Gloss;\n"
324 "#ifdef USECUBEFILTER\n"
325 "uniform samplerCube Texture_Cube;\n"
328 "uniform sampler2D Texture_FogMask;\n"
331 "varying vec2 TexCoord;\n"
332 "varying vec3 CubeVector;\n"
333 "varying vec3 LightVector;\n"
334 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
335 "varying vec3 EyeVector;\n"
342 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
343 " // center and sharp falloff at the edge, this is about the most efficient\n"
344 " // we can get away with as far as providing illumination.\n"
346 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
347 " // provide significant illumination, large = slow = pain.\n"
348 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
352 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
355 "#ifdef USEOFFSETMAPPING\n"
356 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
357 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
358 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
359 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
360 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
361 "#define TexCoord TexCoordOffset\n"
364 " // get the texels - with a blendmap we'd need to blend multiple here\n"
365 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
366 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
367 "#ifdef USESPECULAR\n"
368 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
371 " // calculate shading\n"
372 " vec3 diffusenormal = normalize(LightVector);\n"
373 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
374 "#ifdef USESPECULAR\n"
375 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
378 "#ifdef USECUBEFILTER\n"
379 " // apply light cubemap filter\n"
380 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
383 " // calculate fragment color\n"
384 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
388 void r_shadow_start(void)
391 // allocate vertex processing arrays
393 r_shadow_normalcubetexture = NULL;
394 r_shadow_attenuation2dtexture = NULL;
395 r_shadow_attenuation3dtexture = NULL;
396 r_shadow_blankwhitecubetexture = NULL;
397 r_shadow_texturepool = NULL;
398 r_shadow_filters_texturepool = NULL;
399 R_Shadow_ValidateCvars();
400 R_Shadow_MakeTextures();
401 maxshadowelements = 0;
402 shadowelements = NULL;
410 shadowmarklist = NULL;
412 r_shadow_buffer_numclusterpvsbytes = 0;
413 r_shadow_buffer_clusterpvs = NULL;
414 r_shadow_buffer_clusterlist = NULL;
415 r_shadow_buffer_numsurfacepvsbytes = 0;
416 r_shadow_buffer_surfacepvs = NULL;
417 r_shadow_buffer_surfacelist = NULL;
418 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
419 r_shadow_program_light[i] = 0;
420 if (gl_support_fragment_shader)
422 char *vertstring, *fragstring;
423 int vertstrings_count;
424 int fragstrings_count;
425 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
426 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
427 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
428 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
429 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
431 vertstrings_count = 0;
432 fragstrings_count = 0;
433 if (i & SHADERPERMUTATION_SPECULAR)
435 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
436 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
438 if (i & SHADERPERMUTATION_FOG)
440 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
441 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
443 if (i & SHADERPERMUTATION_CUBEFILTER)
445 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
446 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
448 if (i & SHADERPERMUTATION_OFFSETMAPPING)
450 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
451 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
453 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
454 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
455 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
456 if (!r_shadow_program_light[i])
458 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
461 qglUseProgramObjectARB(r_shadow_program_light[i]);
462 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
463 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
464 if (i & SHADERPERMUTATION_SPECULAR)
466 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
468 if (i & SHADERPERMUTATION_CUBEFILTER)
470 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
472 if (i & SHADERPERMUTATION_FOG)
474 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
477 qglUseProgramObjectARB(0);
479 Mem_Free(fragstring);
481 Mem_Free(vertstring);
485 void r_shadow_shutdown(void)
488 R_Shadow_UncompileWorldLights();
489 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
491 if (r_shadow_program_light[i])
493 GL_Backend_FreeProgram(r_shadow_program_light[i]);
494 r_shadow_program_light[i] = 0;
498 r_shadow_normalcubetexture = NULL;
499 r_shadow_attenuation2dtexture = NULL;
500 r_shadow_attenuation3dtexture = NULL;
501 r_shadow_blankwhitecubetexture = NULL;
502 R_FreeTexturePool(&r_shadow_texturepool);
503 R_FreeTexturePool(&r_shadow_filters_texturepool);
504 maxshadowelements = 0;
506 Mem_Free(shadowelements);
507 shadowelements = NULL;
510 Mem_Free(vertexupdate);
513 Mem_Free(vertexremap);
519 Mem_Free(shadowmark);
522 Mem_Free(shadowmarklist);
523 shadowmarklist = NULL;
525 r_shadow_buffer_numclusterpvsbytes = 0;
526 if (r_shadow_buffer_clusterpvs)
527 Mem_Free(r_shadow_buffer_clusterpvs);
528 r_shadow_buffer_clusterpvs = NULL;
529 if (r_shadow_buffer_clusterlist)
530 Mem_Free(r_shadow_buffer_clusterlist);
531 r_shadow_buffer_clusterlist = NULL;
532 r_shadow_buffer_numsurfacepvsbytes = 0;
533 if (r_shadow_buffer_surfacepvs)
534 Mem_Free(r_shadow_buffer_surfacepvs);
535 r_shadow_buffer_surfacepvs = NULL;
536 if (r_shadow_buffer_surfacelist)
537 Mem_Free(r_shadow_buffer_surfacelist);
538 r_shadow_buffer_surfacelist = NULL;
541 void r_shadow_newmap(void)
545 void R_Shadow_Help_f(void)
548 "Documentation on r_shadow system:\n"
550 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
551 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
552 "r_shadow_debuglight : render only this light number (-1 = all)\n"
553 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
554 "r_shadow_gloss2intensity : brightness of forced gloss\n"
555 "r_shadow_glossintensity : brightness of textured gloss\n"
556 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
557 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
558 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
559 "r_shadow_portallight : use portal visibility for static light precomputation\n"
560 "r_shadow_projectdistance : shadow volume projection distance\n"
561 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
562 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
563 "r_shadow_realtime_world : use high quality world lighting mode\n"
564 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
565 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
566 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
567 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
568 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
569 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
570 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
571 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
572 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
573 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
574 "r_shadow_scissor : use scissor optimization\n"
575 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
576 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
577 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
578 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
579 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
580 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
582 "r_shadow_help : this help\n"
586 void R_Shadow_Init(void)
588 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
589 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
590 Cvar_RegisterVariable(&r_shadow_cull);
591 Cvar_RegisterVariable(&r_shadow_debuglight);
592 Cvar_RegisterVariable(&r_shadow_gloss);
593 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
594 Cvar_RegisterVariable(&r_shadow_glossintensity);
595 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
596 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
597 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
598 Cvar_RegisterVariable(&r_shadow_portallight);
599 Cvar_RegisterVariable(&r_shadow_projectdistance);
600 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
601 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
602 Cvar_RegisterVariable(&r_shadow_realtime_world);
603 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
604 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
605 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
606 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
607 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
608 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
609 Cvar_RegisterVariable(&r_shadow_scissor);
610 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
611 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
612 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
613 Cvar_RegisterVariable(&r_shadow_texture3d);
614 Cvar_RegisterVariable(&r_shadow_visiblelighting);
615 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
616 Cvar_RegisterVariable(&r_shadow_glsl);
617 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
618 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
619 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
620 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
621 if (gamemode == GAME_TENEBRAE)
623 Cvar_SetValue("r_shadow_gloss", 2);
624 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
626 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
627 R_Shadow_EditLights_Init();
628 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
629 r_shadow_worldlightchain = NULL;
630 maxshadowelements = 0;
631 shadowelements = NULL;
639 shadowmarklist = NULL;
641 r_shadow_buffer_numclusterpvsbytes = 0;
642 r_shadow_buffer_clusterpvs = NULL;
643 r_shadow_buffer_clusterlist = NULL;
644 r_shadow_buffer_numsurfacepvsbytes = 0;
645 r_shadow_buffer_surfacepvs = NULL;
646 r_shadow_buffer_surfacelist = NULL;
647 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
650 matrix4x4_t matrix_attenuationxyz =
653 {0.5, 0.0, 0.0, 0.5},
654 {0.0, 0.5, 0.0, 0.5},
655 {0.0, 0.0, 0.5, 0.5},
660 matrix4x4_t matrix_attenuationz =
663 {0.0, 0.0, 0.5, 0.5},
664 {0.0, 0.0, 0.0, 0.5},
665 {0.0, 0.0, 0.0, 0.5},
670 int *R_Shadow_ResizeShadowElements(int numtris)
672 // make sure shadowelements is big enough for this volume
673 if (maxshadowelements < numtris * 24)
675 maxshadowelements = numtris * 24;
677 Mem_Free(shadowelements);
678 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
680 return shadowelements;
683 void R_Shadow_EnlargeClusterSurfaceBuffer(int numclusters, int numsurfaces)
685 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
686 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
687 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
689 if (r_shadow_buffer_clusterpvs)
690 Mem_Free(r_shadow_buffer_clusterpvs);
691 if (r_shadow_buffer_clusterlist)
692 Mem_Free(r_shadow_buffer_clusterlist);
693 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
694 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
695 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
697 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
699 if (r_shadow_buffer_surfacepvs)
700 Mem_Free(r_shadow_buffer_surfacepvs);
701 if (r_shadow_buffer_surfacelist)
702 Mem_Free(r_shadow_buffer_surfacelist);
703 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
704 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
705 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
709 void R_Shadow_PrepareShadowMark(int numtris)
711 // make sure shadowmark is big enough for this volume
712 if (maxshadowmark < numtris)
714 maxshadowmark = numtris;
716 Mem_Free(shadowmark);
718 Mem_Free(shadowmarklist);
719 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
720 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
724 // if shadowmarkcount wrapped we clear the array and adjust accordingly
725 if (shadowmarkcount == 0)
728 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
733 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
736 int outtriangles = 0, outvertices = 0;
740 if (maxvertexupdate < innumvertices)
742 maxvertexupdate = innumvertices;
744 Mem_Free(vertexupdate);
746 Mem_Free(vertexremap);
747 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
748 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
752 if (vertexupdatenum == 0)
755 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
756 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
759 for (i = 0;i < numshadowmarktris;i++)
760 shadowmark[shadowmarktris[i]] = shadowmarkcount;
762 for (i = 0;i < numshadowmarktris;i++)
764 element = inelement3i + shadowmarktris[i] * 3;
765 // make sure the vertices are created
766 for (j = 0;j < 3;j++)
768 if (vertexupdate[element[j]] != vertexupdatenum)
770 float ratio, direction[3];
771 vertexupdate[element[j]] = vertexupdatenum;
772 vertexremap[element[j]] = outvertices;
773 vertex = invertex3f + element[j] * 3;
774 // project one copy of the vertex to the sphere radius of the light
775 // (FIXME: would projecting it to the light box be better?)
776 VectorSubtract(vertex, projectorigin, direction);
777 ratio = projectdistance / VectorLength(direction);
778 VectorCopy(vertex, outvertex3f);
779 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
786 for (i = 0;i < numshadowmarktris;i++)
788 int remappedelement[3];
790 const int *neighbortriangle;
792 markindex = shadowmarktris[i] * 3;
793 element = inelement3i + markindex;
794 neighbortriangle = inneighbor3i + markindex;
795 // output the front and back triangles
796 outelement3i[0] = vertexremap[element[0]];
797 outelement3i[1] = vertexremap[element[1]];
798 outelement3i[2] = vertexremap[element[2]];
799 outelement3i[3] = vertexremap[element[2]] + 1;
800 outelement3i[4] = vertexremap[element[1]] + 1;
801 outelement3i[5] = vertexremap[element[0]] + 1;
805 // output the sides (facing outward from this triangle)
806 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
808 remappedelement[0] = vertexremap[element[0]];
809 remappedelement[1] = vertexremap[element[1]];
810 outelement3i[0] = remappedelement[1];
811 outelement3i[1] = remappedelement[0];
812 outelement3i[2] = remappedelement[0] + 1;
813 outelement3i[3] = remappedelement[1];
814 outelement3i[4] = remappedelement[0] + 1;
815 outelement3i[5] = remappedelement[1] + 1;
820 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
822 remappedelement[1] = vertexremap[element[1]];
823 remappedelement[2] = vertexremap[element[2]];
824 outelement3i[0] = remappedelement[2];
825 outelement3i[1] = remappedelement[1];
826 outelement3i[2] = remappedelement[1] + 1;
827 outelement3i[3] = remappedelement[2];
828 outelement3i[4] = remappedelement[1] + 1;
829 outelement3i[5] = remappedelement[2] + 1;
834 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
836 remappedelement[0] = vertexremap[element[0]];
837 remappedelement[2] = vertexremap[element[2]];
838 outelement3i[0] = remappedelement[0];
839 outelement3i[1] = remappedelement[2];
840 outelement3i[2] = remappedelement[2] + 1;
841 outelement3i[3] = remappedelement[0];
842 outelement3i[4] = remappedelement[2] + 1;
843 outelement3i[5] = remappedelement[0] + 1;
850 *outnumvertices = outvertices;
854 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)
857 if (projectdistance < 0.1)
859 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
862 if (!numverts || !nummarktris)
864 // make sure shadowelements is big enough for this volume
865 if (maxshadowelements < nummarktris * 24)
866 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
867 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
868 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
871 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
876 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
878 tend = firsttriangle + numtris;
879 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
880 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
881 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
883 // surface box entirely inside light box, no box cull
884 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
885 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
886 shadowmarklist[numshadowmark++] = t;
890 // surface box not entirely inside light box, cull each triangle
891 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
893 v[0] = invertex3f + e[0] * 3;
894 v[1] = invertex3f + e[1] * 3;
895 v[2] = invertex3f + e[2] * 3;
896 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
897 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
898 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
899 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
900 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
901 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
902 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
903 shadowmarklist[numshadowmark++] = t;
908 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
911 if (r_shadow_compilingrtlight)
913 // if we're compiling an rtlight, capture the mesh
914 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
917 memset(&m, 0, sizeof(m));
918 m.pointer_vertex = vertex3f;
920 GL_LockArrays(0, numvertices);
921 if (r_shadowstage == SHADOWSTAGE_STENCIL)
923 // increment stencil if backface is behind depthbuffer
924 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
925 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
926 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
928 c_rt_shadowtris += numtriangles;
929 // decrement stencil if frontface is behind depthbuffer
930 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
931 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
933 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
935 c_rt_shadowtris += numtriangles;
939 static void R_Shadow_MakeTextures(void)
941 int x, y, z, d, side;
942 float v[3], s, t, intensity;
944 R_FreeTexturePool(&r_shadow_texturepool);
945 r_shadow_texturepool = R_AllocTexturePool();
946 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
947 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
949 #define ATTEN2DSIZE 64
950 #define ATTEN3DSIZE 32
951 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
952 r_shadow_blankwhitecubetexture = NULL;
953 r_shadow_normalcubetexture = NULL;
954 if (gl_texturecubemap)
956 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
957 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
958 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
959 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
960 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
961 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
962 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
963 for (side = 0;side < 6;side++)
965 for (y = 0;y < NORMSIZE;y++)
967 for (x = 0;x < NORMSIZE;x++)
969 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
970 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1004 intensity = 127.0f / sqrt(DotProduct(v, v));
1005 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1006 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1007 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1008 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1012 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1014 for (y = 0;y < ATTEN2DSIZE;y++)
1016 for (x = 0;x < ATTEN2DSIZE;x++)
1018 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1019 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1021 intensity = 1.0f - sqrt(DotProduct(v, v));
1023 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1024 d = bound(0, intensity, 255);
1025 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1026 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1027 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1028 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1031 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1032 if (r_shadow_texture3d.integer)
1034 for (z = 0;z < ATTEN3DSIZE;z++)
1036 for (y = 0;y < ATTEN3DSIZE;y++)
1038 for (x = 0;x < ATTEN3DSIZE;x++)
1040 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1041 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1042 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1043 intensity = 1.0f - sqrt(DotProduct(v, v));
1045 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1046 d = bound(0, intensity, 255);
1047 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1048 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1049 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1050 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1054 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1059 void R_Shadow_ValidateCvars(void)
1061 if (r_shadow_texture3d.integer && !gl_texture3d)
1062 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1063 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1064 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1067 void R_Shadow_Stage_Begin(void)
1071 R_Shadow_ValidateCvars();
1073 if (!r_shadow_attenuation2dtexture
1074 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1075 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1076 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1077 R_Shadow_MakeTextures();
1079 memset(&m, 0, sizeof(m));
1080 GL_BlendFunc(GL_ONE, GL_ZERO);
1081 GL_DepthMask(false);
1084 GL_Color(0, 0, 0, 1);
1085 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1086 qglEnable(GL_CULL_FACE);
1087 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1088 r_shadowstage = SHADOWSTAGE_NONE;
1091 void R_Shadow_Stage_ShadowVolumes(void)
1094 memset(&m, 0, sizeof(m));
1096 GL_Color(1, 1, 1, 1);
1097 GL_ColorMask(0, 0, 0, 0);
1098 GL_BlendFunc(GL_ONE, GL_ZERO);
1099 GL_DepthMask(false);
1101 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1102 //if (r_shadow_shadow_polygonoffset.value != 0)
1104 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1105 // qglEnable(GL_POLYGON_OFFSET_FILL);
1108 // qglDisable(GL_POLYGON_OFFSET_FILL);
1109 qglDepthFunc(GL_LESS);
1110 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1111 qglEnable(GL_STENCIL_TEST);
1112 qglStencilFunc(GL_ALWAYS, 128, ~0);
1113 if (gl_ext_stenciltwoside.integer)
1115 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1116 qglDisable(GL_CULL_FACE);
1117 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1118 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1120 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1121 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1123 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1127 r_shadowstage = SHADOWSTAGE_STENCIL;
1128 qglEnable(GL_CULL_FACE);
1130 // this is changed by every shadow render so its value here is unimportant
1131 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1133 GL_Clear(GL_STENCIL_BUFFER_BIT);
1135 // LordHavoc note: many shadow volumes reside entirely inside the world
1136 // (that is to say they are entirely bounded by their lit surfaces),
1137 // which can be optimized by handling things as an inverted light volume,
1138 // with the shadow boundaries of the world being simulated by an altered
1139 // (129) bias to stencil clearing on such lights
1140 // FIXME: generate inverted light volumes for use as shadow volumes and
1141 // optimize for them as noted above
1144 void R_Shadow_Stage_Light(int shadowtest)
1147 memset(&m, 0, sizeof(m));
1149 GL_BlendFunc(GL_ONE, GL_ONE);
1150 GL_DepthMask(false);
1152 qglPolygonOffset(0, 0);
1153 //qglDisable(GL_POLYGON_OFFSET_FILL);
1154 GL_Color(1, 1, 1, 1);
1155 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1156 qglDepthFunc(GL_EQUAL);
1157 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1158 qglEnable(GL_CULL_FACE);
1160 qglEnable(GL_STENCIL_TEST);
1162 qglDisable(GL_STENCIL_TEST);
1163 if (gl_support_stenciltwoside)
1164 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1166 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1167 // only draw light where this geometry was already rendered AND the
1168 // stencil is 128 (values other than this mean shadow)
1169 qglStencilFunc(GL_EQUAL, 128, ~0);
1170 r_shadowstage = SHADOWSTAGE_LIGHT;
1174 void R_Shadow_Stage_End(void)
1177 memset(&m, 0, sizeof(m));
1179 GL_BlendFunc(GL_ONE, GL_ZERO);
1182 qglPolygonOffset(0, 0);
1183 //qglDisable(GL_POLYGON_OFFSET_FILL);
1184 GL_Color(1, 1, 1, 1);
1185 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1186 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1187 qglDepthFunc(GL_LEQUAL);
1188 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1189 qglDisable(GL_STENCIL_TEST);
1190 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1191 if (gl_support_stenciltwoside)
1192 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1194 qglStencilFunc(GL_ALWAYS, 128, ~0);
1195 r_shadowstage = SHADOWSTAGE_NONE;
1198 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1200 int i, ix1, iy1, ix2, iy2;
1201 float x1, y1, x2, y2, x, y, f;
1202 vec3_t smins, smaxs;
1204 if (!r_shadow_scissor.integer)
1206 // if view is inside the box, just say yes it's visible
1207 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1209 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1212 for (i = 0;i < 3;i++)
1214 if (r_viewforward[i] >= 0)
1225 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1226 if (DotProduct(r_viewforward, v2) <= f)
1228 // entirely behind nearclip plane
1231 if (DotProduct(r_viewforward, v) >= f)
1233 // entirely infront of nearclip plane
1234 x1 = y1 = x2 = y2 = 0;
1235 for (i = 0;i < 8;i++)
1237 v[0] = (i & 1) ? mins[0] : maxs[0];
1238 v[1] = (i & 2) ? mins[1] : maxs[1];
1239 v[2] = (i & 4) ? mins[2] : maxs[2];
1241 GL_TransformToScreen(v, v2);
1242 //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]);
1261 // clipped by nearclip plane
1262 // this is nasty and crude...
1263 // create viewspace bbox
1264 for (i = 0;i < 8;i++)
1266 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1267 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1268 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1269 v2[0] = -DotProduct(v, r_viewleft);
1270 v2[1] = DotProduct(v, r_viewup);
1271 v2[2] = DotProduct(v, r_viewforward);
1274 if (smins[0] > v2[0]) smins[0] = v2[0];
1275 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1276 if (smins[1] > v2[1]) smins[1] = v2[1];
1277 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1278 if (smins[2] > v2[2]) smins[2] = v2[2];
1279 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1283 smins[0] = smaxs[0] = v2[0];
1284 smins[1] = smaxs[1] = v2[1];
1285 smins[2] = smaxs[2] = v2[2];
1288 // now we have a bbox in viewspace
1289 // clip it to the view plane
1292 // return true if that culled the box
1293 if (smins[2] >= smaxs[2])
1295 // ok some of it is infront of the view, transform each corner back to
1296 // worldspace and then to screenspace and make screen rect
1297 // initialize these variables just to avoid compiler warnings
1298 x1 = y1 = x2 = y2 = 0;
1299 for (i = 0;i < 8;i++)
1301 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1302 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1303 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1304 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1305 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1306 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1308 GL_TransformToScreen(v, v2);
1309 //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]);
1326 // this code doesn't handle boxes with any points behind view properly
1327 x1 = 1000;x2 = -1000;
1328 y1 = 1000;y2 = -1000;
1329 for (i = 0;i < 8;i++)
1331 v[0] = (i & 1) ? mins[0] : maxs[0];
1332 v[1] = (i & 2) ? mins[1] : maxs[1];
1333 v[2] = (i & 4) ? mins[2] : maxs[2];
1335 GL_TransformToScreen(v, v2);
1336 //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]);
1354 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1355 if (ix1 < r_view_x) ix1 = r_view_x;
1356 if (iy1 < r_view_y) iy1 = r_view_y;
1357 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1358 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1359 if (ix2 <= ix1 || iy2 <= iy1)
1361 // set up the scissor rectangle
1362 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1363 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1364 //qglEnable(GL_SCISSOR_TEST);
1369 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1371 float *color4f = varray_color4f;
1372 float dist, dot, intensity, v[3], n[3];
1373 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1375 Matrix4x4_Transform(m, vertex3f, v);
1376 if ((dist = DotProduct(v, v)) < 1)
1378 Matrix4x4_Transform3x3(m, normal3f, n);
1379 if ((dot = DotProduct(n, v)) > 0)
1382 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1383 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1384 VectorScale(lightcolor, intensity, color4f);
1389 VectorClear(color4f);
1395 VectorClear(color4f);
1401 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1403 float *color4f = varray_color4f;
1404 float dist, dot, intensity, v[3], n[3];
1405 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1407 Matrix4x4_Transform(m, vertex3f, v);
1408 if ((dist = fabs(v[2])) < 1)
1410 Matrix4x4_Transform3x3(m, normal3f, n);
1411 if ((dot = DotProduct(n, v)) > 0)
1413 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1414 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1415 VectorScale(lightcolor, intensity, color4f);
1420 VectorClear(color4f);
1426 VectorClear(color4f);
1432 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1434 float *color4f = varray_color4f;
1435 float dot, intensity, v[3], n[3];
1436 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1438 Matrix4x4_Transform(m, vertex3f, v);
1439 Matrix4x4_Transform3x3(m, normal3f, n);
1440 if ((dot = DotProduct(n, v)) > 0)
1442 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1443 VectorScale(lightcolor, intensity, color4f);
1448 VectorClear(color4f);
1454 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1456 float *color4f = varray_color4f;
1457 float dist, intensity, v[3];
1458 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1460 Matrix4x4_Transform(m, vertex3f, v);
1461 if ((dist = DotProduct(v, v)) < 1)
1464 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1465 VectorScale(lightcolor, intensity, color4f);
1470 VectorClear(color4f);
1476 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1478 float *color4f = varray_color4f;
1479 float dist, intensity, v[3];
1480 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1482 Matrix4x4_Transform(m, vertex3f, v);
1483 if ((dist = fabs(v[2])) < 1)
1485 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1486 VectorScale(lightcolor, intensity, color4f);
1491 VectorClear(color4f);
1497 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1498 #define USETEXMATRIX
1500 #ifndef USETEXMATRIX
1501 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1502 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1503 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1507 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1508 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1509 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1516 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1520 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1521 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1529 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)
1533 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1535 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1536 // the cubemap normalizes this for us
1537 out3f[0] = DotProduct(svector3f, lightdir);
1538 out3f[1] = DotProduct(tvector3f, lightdir);
1539 out3f[2] = DotProduct(normal3f, lightdir);
1543 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)
1546 float lightdir[3], eyedir[3], halfdir[3];
1547 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1549 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1550 VectorNormalizeFast(lightdir);
1551 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1552 VectorNormalizeFast(eyedir);
1553 VectorAdd(lightdir, eyedir, halfdir);
1554 // the cubemap normalizes this for us
1555 out3f[0] = DotProduct(svector3f, halfdir);
1556 out3f[1] = DotProduct(tvector3f, halfdir);
1557 out3f[2] = DotProduct(normal3f, halfdir);
1561 void R_Shadow_RenderLighting(int firstvertex, int numvertices, 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 *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int visiblelighting)
1564 float color[3], color2[3], colorscale;
1567 basetexture = r_texture_white;
1569 bumptexture = r_texture_blanknormalmap;
1570 if (!lightcolorbase)
1571 lightcolorbase = vec3_origin;
1572 if (!lightcolorpants)
1573 lightcolorpants = vec3_origin;
1574 if (!lightcolorshirt)
1575 lightcolorshirt = vec3_origin;
1576 specularscale *= r_shadow_glossintensity.value;
1579 if (r_shadow_gloss.integer >= 2)
1581 glosstexture = r_texture_white;
1582 specularscale *= r_shadow_gloss2intensity.value;
1586 glosstexture = r_texture_black;
1590 if (r_shadow_gloss.integer < 1)
1593 lightcubemap = r_shadow_blankwhitecubetexture;
1594 if ((ambientscale + diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1596 if (visiblelighting)
1599 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1600 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1601 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1603 // TODO: add direct pants/shirt rendering
1604 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1605 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1606 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1607 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1609 bumptexture = r_texture_blanknormalmap;
1611 glosstexture = r_texture_white;
1614 colorscale = ambientscale;
1615 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1618 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1621 else if (r_textureunits.integer >= 4 && lightcubemap)
1624 else if (r_textureunits.integer >= 3 && !lightcubemap)
1629 VectorScale(lightcolorbase, colorscale, color2);
1630 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1635 colorscale = diffusescale;
1636 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1638 // 3/2 3D combine path (Geforce3, Radeon 8500)
1641 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1643 // 1/2/2 3D combine path (original Radeon)
1646 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1648 // 2/2 3D combine path (original Radeon)
1651 else if (r_textureunits.integer >= 4)
1653 // 4/2 2D combine path (Geforce3, Radeon 8500)
1658 // 2/2/2 2D combine path (any dot3 card)
1661 VectorScale(lightcolorbase, colorscale, color2);
1662 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1665 if (specularscale && glosstexture != r_texture_black)
1667 //if (gl_support_blendsquare)
1669 colorscale = specularscale;
1670 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1672 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1676 VectorScale(lightcolorbase, colorscale, color2);
1677 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1684 // TODO: add direct pants/shirt rendering
1685 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1686 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1687 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1688 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1691 VectorScale(lightcolorbase, ambientscale, color2);
1692 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1697 VectorScale(lightcolorbase, diffusescale, color2);
1698 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1704 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1705 memset(&m, 0, sizeof(m));
1706 m.pointer_vertex = vertex3f;
1708 GL_LockArrays(firstvertex, numvertices);
1709 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1710 GL_LockArrays(0, 0);
1714 // FIXME: support EF_NODEPTHTEST
1715 GL_DepthMask(false);
1717 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1719 unsigned int perm, prog;
1720 // GLSL shader path (GFFX5200, Radeon 9500)
1721 memset(&m, 0, sizeof(m));
1722 m.pointer_vertex = vertex3f;
1723 m.pointer_texcoord[0] = texcoord2f;
1724 m.pointer_texcoord3f[1] = svector3f;
1725 m.pointer_texcoord3f[2] = tvector3f;
1726 m.pointer_texcoord3f[3] = normal3f;
1727 m.tex[0] = R_GetTexture(bumptexture);
1728 m.tex[1] = R_GetTexture(basetexture);
1729 m.tex[2] = R_GetTexture(glosstexture);
1730 m.texcubemap[3] = R_GetTexture(lightcubemap);
1731 // TODO: support fog (after renderer is converted to texture fog)
1732 m.tex[4] = R_GetTexture(r_texture_white);
1733 m.texmatrix[3] = *matrix_modeltolight;
1735 GL_BlendFunc(GL_ONE, GL_ONE);
1736 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1739 // only add a feature to the permutation if that permutation exists
1740 // (otherwise it might end up not using a shader at all, which looks
1741 // worse than using less features)
1742 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1743 perm |= SHADERPERMUTATION_SPECULAR;
1744 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1745 // perm |= SHADERPERMUTATION_FOG;
1746 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1747 perm |= SHADERPERMUTATION_CUBEFILTER;
1748 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1749 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1750 prog = r_shadow_program_light[perm];
1751 qglUseProgramObjectARB(prog);CHECKGLERROR
1752 // TODO: support fog (after renderer is converted to texture fog)
1753 if (perm & SHADERPERMUTATION_FOG)
1755 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1757 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1758 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1759 if (perm & SHADERPERMUTATION_SPECULAR)
1761 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1762 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1764 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1765 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1766 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1768 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1770 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1772 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1773 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1776 GL_LockArrays(firstvertex, numvertices);
1777 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1779 c_rt_lighttris += numtriangles;
1780 // TODO: add direct pants/shirt rendering
1781 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1783 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1784 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1785 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1787 c_rt_lighttris += numtriangles;
1789 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1791 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1792 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1793 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1795 c_rt_lighttris += numtriangles;
1797 GL_LockArrays(0, 0);
1798 qglUseProgramObjectARB(0);
1799 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1800 qglBegin(GL_TRIANGLES);
1804 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1806 // TODO: add direct pants/shirt rendering
1807 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1808 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1809 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1810 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1812 bumptexture = r_texture_blanknormalmap;
1814 glosstexture = r_texture_white;
1818 colorscale = ambientscale;
1819 // colorscale accounts for how much we multiply the brightness
1822 // mult is how many times the final pass of the lighting will be
1823 // performed to get more brightness than otherwise possible.
1825 // Limit mult to 64 for sanity sake.
1826 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1828 // 3 3D combine path (Geforce3, Radeon 8500)
1829 memset(&m, 0, sizeof(m));
1830 m.pointer_vertex = vertex3f;
1831 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1833 m.pointer_texcoord3f[0] = vertex3f;
1834 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1836 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1837 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1839 m.tex[1] = R_GetTexture(basetexture);
1840 m.pointer_texcoord[1] = texcoord2f;
1841 m.texcubemap[2] = R_GetTexture(lightcubemap);
1843 m.pointer_texcoord3f[2] = vertex3f;
1844 m.texmatrix[2] = *matrix_modeltolight;
1846 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1847 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1849 GL_BlendFunc(GL_ONE, GL_ONE);
1851 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1853 // 2 3D combine path (Geforce3, original Radeon)
1854 memset(&m, 0, sizeof(m));
1855 m.pointer_vertex = vertex3f;
1856 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1858 m.pointer_texcoord3f[0] = vertex3f;
1859 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1861 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1862 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1864 m.tex[1] = R_GetTexture(basetexture);
1865 m.pointer_texcoord[1] = texcoord2f;
1866 GL_BlendFunc(GL_ONE, GL_ONE);
1868 else if (r_textureunits.integer >= 4 && lightcubemap)
1870 // 4 2D combine path (Geforce3, Radeon 8500)
1871 memset(&m, 0, sizeof(m));
1872 m.pointer_vertex = vertex3f;
1873 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1875 m.pointer_texcoord3f[0] = vertex3f;
1876 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1878 m.pointer_texcoord[0] = varray_texcoord2f[0];
1879 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1881 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1883 m.pointer_texcoord3f[1] = vertex3f;
1884 m.texmatrix[1] = *matrix_modeltoattenuationz;
1886 m.pointer_texcoord[1] = varray_texcoord2f[1];
1887 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1889 m.tex[2] = R_GetTexture(basetexture);
1890 m.pointer_texcoord[2] = texcoord2f;
1893 m.texcubemap[3] = R_GetTexture(lightcubemap);
1895 m.pointer_texcoord3f[3] = vertex3f;
1896 m.texmatrix[3] = *matrix_modeltolight;
1898 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1899 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1902 GL_BlendFunc(GL_ONE, GL_ONE);
1904 else if (r_textureunits.integer >= 3 && !lightcubemap)
1906 // 3 2D combine path (Geforce3, original Radeon)
1907 memset(&m, 0, sizeof(m));
1908 m.pointer_vertex = vertex3f;
1909 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1911 m.pointer_texcoord3f[0] = vertex3f;
1912 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1914 m.pointer_texcoord[0] = varray_texcoord2f[0];
1915 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1917 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1919 m.pointer_texcoord3f[1] = vertex3f;
1920 m.texmatrix[1] = *matrix_modeltoattenuationz;
1922 m.pointer_texcoord[1] = varray_texcoord2f[1];
1923 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1925 m.tex[2] = R_GetTexture(basetexture);
1926 m.pointer_texcoord[2] = texcoord2f;
1927 GL_BlendFunc(GL_ONE, GL_ONE);
1931 // 2/2/2 2D combine path (any dot3 card)
1932 memset(&m, 0, sizeof(m));
1933 m.pointer_vertex = vertex3f;
1934 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1936 m.pointer_texcoord3f[0] = vertex3f;
1937 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1939 m.pointer_texcoord[0] = varray_texcoord2f[0];
1940 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1942 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1944 m.pointer_texcoord3f[1] = vertex3f;
1945 m.texmatrix[1] = *matrix_modeltoattenuationz;
1947 m.pointer_texcoord[1] = varray_texcoord2f[1];
1948 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1951 GL_ColorMask(0,0,0,1);
1952 GL_BlendFunc(GL_ONE, GL_ZERO);
1953 GL_LockArrays(firstvertex, numvertices);
1954 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1955 GL_LockArrays(0, 0);
1957 c_rt_lighttris += numtriangles;
1959 memset(&m, 0, sizeof(m));
1960 m.pointer_vertex = vertex3f;
1961 m.tex[0] = R_GetTexture(basetexture);
1962 m.pointer_texcoord[0] = texcoord2f;
1965 m.texcubemap[1] = R_GetTexture(lightcubemap);
1967 m.pointer_texcoord3f[1] = vertex3f;
1968 m.texmatrix[1] = *matrix_modeltolight;
1970 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1971 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1974 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1976 // this final code is shared
1978 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1979 VectorScale(lightcolorbase, colorscale, color2);
1980 GL_LockArrays(firstvertex, numvertices);
1981 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1983 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1984 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1986 c_rt_lighttris += numtriangles;
1988 GL_LockArrays(0, 0);
1993 colorscale = diffusescale;
1994 // colorscale accounts for how much we multiply the brightness
1997 // mult is how many times the final pass of the lighting will be
1998 // performed to get more brightness than otherwise possible.
2000 // Limit mult to 64 for sanity sake.
2001 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2003 // 3/2 3D combine path (Geforce3, Radeon 8500)
2004 memset(&m, 0, sizeof(m));
2005 m.pointer_vertex = vertex3f;
2006 m.tex[0] = R_GetTexture(bumptexture);
2007 m.texcombinergb[0] = GL_REPLACE;
2008 m.pointer_texcoord[0] = texcoord2f;
2009 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2010 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2011 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2012 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2013 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2015 m.pointer_texcoord3f[2] = vertex3f;
2016 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2018 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
2019 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2022 GL_ColorMask(0,0,0,1);
2023 GL_BlendFunc(GL_ONE, GL_ZERO);
2024 GL_LockArrays(firstvertex, numvertices);
2025 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2026 GL_LockArrays(0, 0);
2028 c_rt_lighttris += numtriangles;
2030 memset(&m, 0, sizeof(m));
2031 m.pointer_vertex = vertex3f;
2032 m.tex[0] = R_GetTexture(basetexture);
2033 m.pointer_texcoord[0] = texcoord2f;
2036 m.texcubemap[1] = R_GetTexture(lightcubemap);
2038 m.pointer_texcoord3f[1] = vertex3f;
2039 m.texmatrix[1] = *matrix_modeltolight;
2041 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2042 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2045 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2047 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
2049 // 1/2/2 3D combine path (original Radeon)
2050 memset(&m, 0, sizeof(m));
2051 m.pointer_vertex = vertex3f;
2052 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2054 m.pointer_texcoord3f[0] = vertex3f;
2055 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2057 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2058 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2061 GL_ColorMask(0,0,0,1);
2062 GL_BlendFunc(GL_ONE, GL_ZERO);
2063 GL_LockArrays(firstvertex, numvertices);
2064 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2065 GL_LockArrays(0, 0);
2067 c_rt_lighttris += numtriangles;
2069 memset(&m, 0, sizeof(m));
2070 m.pointer_vertex = vertex3f;
2071 m.tex[0] = R_GetTexture(bumptexture);
2072 m.texcombinergb[0] = GL_REPLACE;
2073 m.pointer_texcoord[0] = texcoord2f;
2074 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2075 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2076 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2077 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2079 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2080 GL_LockArrays(firstvertex, numvertices);
2081 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2082 GL_LockArrays(0, 0);
2084 c_rt_lighttris += numtriangles;
2086 memset(&m, 0, sizeof(m));
2087 m.pointer_vertex = vertex3f;
2088 m.tex[0] = R_GetTexture(basetexture);
2089 m.pointer_texcoord[0] = texcoord2f;
2092 m.texcubemap[1] = R_GetTexture(lightcubemap);
2094 m.pointer_texcoord3f[1] = vertex3f;
2095 m.texmatrix[1] = *matrix_modeltolight;
2097 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2098 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2101 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2103 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
2105 // 2/2 3D combine path (original Radeon)
2106 memset(&m, 0, sizeof(m));
2107 m.pointer_vertex = vertex3f;
2108 m.tex[0] = R_GetTexture(bumptexture);
2109 m.texcombinergb[0] = GL_REPLACE;
2110 m.pointer_texcoord[0] = texcoord2f;
2111 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2112 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2113 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2114 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2116 GL_ColorMask(0,0,0,1);
2117 GL_BlendFunc(GL_ONE, GL_ZERO);
2118 GL_LockArrays(firstvertex, numvertices);
2119 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2120 GL_LockArrays(0, 0);
2122 c_rt_lighttris += numtriangles;
2124 memset(&m, 0, sizeof(m));
2125 m.pointer_vertex = vertex3f;
2126 m.tex[0] = R_GetTexture(basetexture);
2127 m.pointer_texcoord[0] = texcoord2f;
2128 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2130 m.pointer_texcoord3f[1] = vertex3f;
2131 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2133 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2134 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2136 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2138 else if (r_textureunits.integer >= 4)
2140 // 4/2 2D combine path (Geforce3, Radeon 8500)
2141 memset(&m, 0, sizeof(m));
2142 m.pointer_vertex = vertex3f;
2143 m.tex[0] = R_GetTexture(bumptexture);
2144 m.texcombinergb[0] = GL_REPLACE;
2145 m.pointer_texcoord[0] = texcoord2f;
2146 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2147 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2148 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2149 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2150 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2152 m.pointer_texcoord3f[2] = vertex3f;
2153 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2155 m.pointer_texcoord[2] = varray_texcoord2f[2];
2156 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2158 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2160 m.pointer_texcoord3f[3] = vertex3f;
2161 m.texmatrix[3] = *matrix_modeltoattenuationz;
2163 m.pointer_texcoord[3] = varray_texcoord2f[3];
2164 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2167 GL_ColorMask(0,0,0,1);
2168 GL_BlendFunc(GL_ONE, GL_ZERO);
2169 GL_LockArrays(firstvertex, numvertices);
2170 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2171 GL_LockArrays(0, 0);
2173 c_rt_lighttris += numtriangles;
2175 memset(&m, 0, sizeof(m));
2176 m.pointer_vertex = vertex3f;
2177 m.tex[0] = R_GetTexture(basetexture);
2178 m.pointer_texcoord[0] = texcoord2f;
2181 m.texcubemap[1] = R_GetTexture(lightcubemap);
2183 m.pointer_texcoord3f[1] = vertex3f;
2184 m.texmatrix[1] = *matrix_modeltolight;
2186 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2187 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2190 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2194 // 2/2/2 2D combine path (any dot3 card)
2195 memset(&m, 0, sizeof(m));
2196 m.pointer_vertex = vertex3f;
2197 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2199 m.pointer_texcoord3f[0] = vertex3f;
2200 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2202 m.pointer_texcoord[0] = varray_texcoord2f[0];
2203 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2205 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2207 m.pointer_texcoord3f[1] = vertex3f;
2208 m.texmatrix[1] = *matrix_modeltoattenuationz;
2210 m.pointer_texcoord[1] = varray_texcoord2f[1];
2211 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2214 GL_ColorMask(0,0,0,1);
2215 GL_BlendFunc(GL_ONE, GL_ZERO);
2216 GL_LockArrays(firstvertex, numvertices);
2217 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2218 GL_LockArrays(0, 0);
2220 c_rt_lighttris += numtriangles;
2222 memset(&m, 0, sizeof(m));
2223 m.pointer_vertex = vertex3f;
2224 m.tex[0] = R_GetTexture(bumptexture);
2225 m.texcombinergb[0] = GL_REPLACE;
2226 m.pointer_texcoord[0] = texcoord2f;
2227 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2228 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2229 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2230 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2232 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2233 GL_LockArrays(firstvertex, numvertices);
2234 R_Mesh_Draw(firstvertex, numvertices, 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(basetexture);
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] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2254 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2256 // this final code is shared
2258 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2259 VectorScale(lightcolorbase, colorscale, color2);
2260 GL_LockArrays(firstvertex, numvertices);
2261 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2263 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2264 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2266 c_rt_lighttris += numtriangles;
2268 GL_LockArrays(0, 0);
2270 if (specularscale && glosstexture != r_texture_black)
2272 // FIXME: detect blendsquare!
2273 //if (gl_support_blendsquare)
2275 colorscale = specularscale;
2277 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2279 // 2/0/0/1/2 3D combine blendsquare path
2280 memset(&m, 0, sizeof(m));
2281 m.pointer_vertex = vertex3f;
2282 m.tex[0] = R_GetTexture(bumptexture);
2283 m.pointer_texcoord[0] = texcoord2f;
2284 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2285 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2286 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2287 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2289 GL_ColorMask(0,0,0,1);
2290 // this squares the result
2291 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2292 GL_LockArrays(firstvertex, numvertices);
2293 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2294 GL_LockArrays(0, 0);
2296 c_rt_lighttris += numtriangles;
2298 memset(&m, 0, sizeof(m));
2299 m.pointer_vertex = vertex3f;
2301 GL_LockArrays(firstvertex, numvertices);
2302 // square alpha in framebuffer a few times to make it shiny
2303 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2304 // these comments are a test run through this math for intensity 0.5
2305 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2306 // 0.25 * 0.25 = 0.0625 (this is another pass)
2307 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2308 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2310 c_rt_lighttris += numtriangles;
2311 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2313 c_rt_lighttris += numtriangles;
2314 GL_LockArrays(0, 0);
2316 memset(&m, 0, sizeof(m));
2317 m.pointer_vertex = vertex3f;
2318 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2320 m.pointer_texcoord3f[0] = vertex3f;
2321 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2323 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2324 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2327 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2328 GL_LockArrays(firstvertex, numvertices);
2329 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2330 GL_LockArrays(0, 0);
2332 c_rt_lighttris += numtriangles;
2334 memset(&m, 0, sizeof(m));
2335 m.pointer_vertex = vertex3f;
2336 m.tex[0] = R_GetTexture(glosstexture);
2337 m.pointer_texcoord[0] = texcoord2f;
2340 m.texcubemap[1] = R_GetTexture(lightcubemap);
2342 m.pointer_texcoord3f[1] = vertex3f;
2343 m.texmatrix[1] = *matrix_modeltolight;
2345 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2346 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2349 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2351 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2353 // 2/0/0/2 3D combine blendsquare path
2354 memset(&m, 0, sizeof(m));
2355 m.pointer_vertex = vertex3f;
2356 m.tex[0] = R_GetTexture(bumptexture);
2357 m.pointer_texcoord[0] = texcoord2f;
2358 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2359 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2360 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2361 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2363 GL_ColorMask(0,0,0,1);
2364 // this squares the result
2365 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2366 GL_LockArrays(firstvertex, numvertices);
2367 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2368 GL_LockArrays(0, 0);
2370 c_rt_lighttris += numtriangles;
2372 memset(&m, 0, sizeof(m));
2373 m.pointer_vertex = vertex3f;
2375 GL_LockArrays(firstvertex, numvertices);
2376 // square alpha in framebuffer a few times to make it shiny
2377 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2378 // these comments are a test run through this math for intensity 0.5
2379 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2380 // 0.25 * 0.25 = 0.0625 (this is another pass)
2381 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2382 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2384 c_rt_lighttris += numtriangles;
2385 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2387 c_rt_lighttris += numtriangles;
2388 GL_LockArrays(0, 0);
2390 memset(&m, 0, sizeof(m));
2391 m.pointer_vertex = vertex3f;
2392 m.tex[0] = R_GetTexture(glosstexture);
2393 m.pointer_texcoord[0] = texcoord2f;
2394 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2396 m.pointer_texcoord3f[1] = vertex3f;
2397 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2399 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2400 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2402 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2406 // 2/0/0/2/2 2D combine blendsquare path
2407 memset(&m, 0, sizeof(m));
2408 m.pointer_vertex = vertex3f;
2409 m.tex[0] = R_GetTexture(bumptexture);
2410 m.pointer_texcoord[0] = texcoord2f;
2411 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2412 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2413 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2414 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2416 GL_ColorMask(0,0,0,1);
2417 // this squares the result
2418 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2419 GL_LockArrays(firstvertex, numvertices);
2420 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2421 GL_LockArrays(0, 0);
2423 c_rt_lighttris += numtriangles;
2425 memset(&m, 0, sizeof(m));
2426 m.pointer_vertex = vertex3f;
2428 GL_LockArrays(firstvertex, numvertices);
2429 // square alpha in framebuffer a few times to make it shiny
2430 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2431 // these comments are a test run through this math for intensity 0.5
2432 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2433 // 0.25 * 0.25 = 0.0625 (this is another pass)
2434 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2435 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2437 c_rt_lighttris += numtriangles;
2438 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2440 c_rt_lighttris += numtriangles;
2441 GL_LockArrays(0, 0);
2443 memset(&m, 0, sizeof(m));
2444 m.pointer_vertex = vertex3f;
2445 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2447 m.pointer_texcoord3f[0] = vertex3f;
2448 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2450 m.pointer_texcoord[0] = varray_texcoord2f[0];
2451 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2453 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2455 m.pointer_texcoord3f[1] = vertex3f;
2456 m.texmatrix[1] = *matrix_modeltoattenuationz;
2458 m.pointer_texcoord[1] = varray_texcoord2f[1];
2459 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2462 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2463 GL_LockArrays(firstvertex, numvertices);
2464 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2465 GL_LockArrays(0, 0);
2467 c_rt_lighttris += numtriangles;
2469 memset(&m, 0, sizeof(m));
2470 m.pointer_vertex = vertex3f;
2471 m.tex[0] = R_GetTexture(glosstexture);
2472 m.pointer_texcoord[0] = texcoord2f;
2475 m.texcubemap[1] = R_GetTexture(lightcubemap);
2477 m.pointer_texcoord3f[1] = vertex3f;
2478 m.texmatrix[1] = *matrix_modeltolight;
2480 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2481 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2484 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2487 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2488 VectorScale(lightcolorbase, colorscale, color2);
2489 GL_LockArrays(firstvertex, numvertices);
2490 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2492 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2493 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2495 c_rt_lighttris += numtriangles;
2497 GL_LockArrays(0, 0);
2503 // TODO: add direct pants/shirt rendering
2504 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2505 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
2506 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2507 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
2510 GL_BlendFunc(GL_ONE, GL_ONE);
2511 VectorScale(lightcolorbase, ambientscale, color2);
2512 memset(&m, 0, sizeof(m));
2513 m.pointer_vertex = vertex3f;
2514 m.tex[0] = R_GetTexture(basetexture);
2515 m.pointer_texcoord[0] = texcoord2f;
2516 if (r_textureunits.integer >= 2)
2519 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2521 m.pointer_texcoord3f[1] = vertex3f;
2522 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2524 m.pointer_texcoord[1] = varray_texcoord2f[1];
2525 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2527 if (r_textureunits.integer >= 3)
2529 // Geforce3/Radeon class but not using dot3
2530 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2532 m.pointer_texcoord3f[2] = vertex3f;
2533 m.texmatrix[2] = *matrix_modeltoattenuationz;
2535 m.pointer_texcoord[2] = varray_texcoord2f[2];
2536 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2540 if (r_textureunits.integer >= 3)
2541 m.pointer_color = NULL;
2543 m.pointer_color = varray_color4f;
2545 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2547 color[0] = bound(0, color2[0], 1);
2548 color[1] = bound(0, color2[1], 1);
2549 color[2] = bound(0, color2[2], 1);
2550 if (r_textureunits.integer >= 3)
2551 GL_Color(color[0], color[1], color[2], 1);
2552 else if (r_textureunits.integer >= 2)
2553 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2555 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2556 GL_LockArrays(firstvertex, numvertices);
2557 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2558 GL_LockArrays(0, 0);
2560 c_rt_lighttris += numtriangles;
2565 GL_BlendFunc(GL_ONE, GL_ONE);
2566 VectorScale(lightcolorbase, diffusescale, color2);
2567 memset(&m, 0, sizeof(m));
2568 m.pointer_vertex = vertex3f;
2569 m.pointer_color = varray_color4f;
2570 m.tex[0] = R_GetTexture(basetexture);
2571 m.pointer_texcoord[0] = texcoord2f;
2572 if (r_textureunits.integer >= 2)
2575 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2577 m.pointer_texcoord3f[1] = vertex3f;
2578 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2580 m.pointer_texcoord[1] = varray_texcoord2f[1];
2581 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2583 if (r_textureunits.integer >= 3)
2585 // Geforce3/Radeon class but not using dot3
2586 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2588 m.pointer_texcoord3f[2] = vertex3f;
2589 m.texmatrix[2] = *matrix_modeltoattenuationz;
2591 m.pointer_texcoord[2] = varray_texcoord2f[2];
2592 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2597 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2599 color[0] = bound(0, color2[0], 1);
2600 color[1] = bound(0, color2[1], 1);
2601 color[2] = bound(0, color2[2], 1);
2602 if (r_textureunits.integer >= 3)
2603 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2604 else if (r_textureunits.integer >= 2)
2605 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2607 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2608 GL_LockArrays(firstvertex, numvertices);
2609 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2610 GL_LockArrays(0, 0);
2612 c_rt_lighttris += numtriangles;
2618 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2622 R_RTLight_Uncompile(rtlight);
2623 memset(rtlight, 0, sizeof(*rtlight));
2625 VectorCopy(light->origin, rtlight->shadoworigin);
2626 VectorCopy(light->color, rtlight->color);
2627 rtlight->radius = light->radius;
2628 //rtlight->cullradius = rtlight->radius;
2629 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2630 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2631 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2632 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2633 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2634 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2635 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2636 rtlight->cubemapname[0] = 0;
2637 if (light->cubemapname[0])
2638 strcpy(rtlight->cubemapname, light->cubemapname);
2639 else if (light->cubemapnum > 0)
2640 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2641 rtlight->shadow = light->shadow;
2642 rtlight->corona = light->corona;
2643 rtlight->style = light->style;
2644 rtlight->isstatic = isstatic;
2645 rtlight->coronasizescale = light->coronasizescale;
2646 rtlight->ambientscale = light->ambientscale;
2647 rtlight->diffusescale = light->diffusescale;
2648 rtlight->specularscale = light->specularscale;
2649 rtlight->flags = light->flags;
2650 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2651 // ConcatScale won't work here because this needs to scale rotate and
2652 // translate, not just rotate
2653 scale = 1.0f / rtlight->radius;
2654 for (k = 0;k < 3;k++)
2655 for (j = 0;j < 4;j++)
2656 rtlight->matrix_worldtolight.m[k][j] *= scale;
2657 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2658 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2660 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2661 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2662 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2663 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2666 // compiles rtlight geometry
2667 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2668 void R_RTLight_Compile(rtlight_t *rtlight)
2670 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numclusterpvsbytes, numsurfaces;
2671 entity_render_t *ent = r_refdef.worldentity;
2672 model_t *model = r_refdef.worldmodel;
2675 // compile the light
2676 rtlight->compiled = true;
2677 rtlight->static_numclusters = 0;
2678 rtlight->static_numclusterpvsbytes = 0;
2679 rtlight->static_clusterlist = NULL;
2680 rtlight->static_clusterpvs = NULL;
2681 rtlight->static_numsurfaces = 0;
2682 rtlight->static_surfacelist = NULL;
2683 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2684 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2685 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2686 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2687 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2688 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2690 if (model && model->GetLightInfo)
2692 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2693 r_shadow_compilingrtlight = rtlight;
2694 R_Shadow_EnlargeClusterSurfaceBuffer(model->brush.num_pvsclusters, model->nummodelsurfaces);
2695 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);
2696 numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2697 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numclusters + numclusterpvsbytes + sizeof(int) * numsurfaces);
2698 rtlight->static_numclusters = numclusters;
2699 rtlight->static_numclusterpvsbytes = numclusterpvsbytes;
2700 rtlight->static_clusterlist = (void *)data;data += sizeof(int) * numclusters;
2701 rtlight->static_clusterpvs = (void *)data;data += numclusterpvsbytes;
2702 rtlight->static_numsurfaces = numsurfaces;
2703 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2705 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2706 if (numclusterpvsbytes)
2707 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2709 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2710 if (model->DrawShadowVolume && rtlight->shadow)
2712 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2713 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2714 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2716 if (model->DrawLight)
2718 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2719 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, 0);
2720 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2722 // switch back to rendering when DrawShadowVolume or DrawLight is called
2723 r_shadow_compilingrtlight = NULL;
2727 // use smallest available cullradius - box radius or light radius
2728 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2729 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2733 if (rtlight->static_meshchain_shadow)
2736 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2739 shadowtris += mesh->numtriangles;
2745 if (rtlight->static_meshchain_light)
2748 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2751 lighttris += mesh->numtriangles;
2755 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);
2758 void R_RTLight_Uncompile(rtlight_t *rtlight)
2760 if (rtlight->compiled)
2762 if (rtlight->static_meshchain_shadow)
2763 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2764 rtlight->static_meshchain_shadow = NULL;
2765 if (rtlight->static_meshchain_light)
2766 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2767 rtlight->static_meshchain_light = NULL;
2768 // these allocations are grouped
2769 if (rtlight->static_clusterlist)
2770 Mem_Free(rtlight->static_clusterlist);
2771 rtlight->static_numclusters = 0;
2772 rtlight->static_numclusterpvsbytes = 0;
2773 rtlight->static_clusterlist = NULL;
2774 rtlight->static_clusterpvs = NULL;
2775 rtlight->static_numsurfaces = 0;
2776 rtlight->static_surfacelist = NULL;
2777 rtlight->compiled = false;
2781 void R_Shadow_UncompileWorldLights(void)
2784 for (light = r_shadow_worldlightchain;light;light = light->next)
2785 R_RTLight_Uncompile(&light->rtlight);
2788 void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
2790 int i, shadow, usestencil;
2791 entity_render_t *ent;
2793 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2794 rtexture_t *cubemaptexture;
2795 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2796 int numclusters, numsurfaces;
2797 int *clusterlist, *surfacelist;
2799 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2803 // skip lights that don't light (corona only lights)
2804 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2807 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2808 VectorScale(rtlight->color, f, lightcolor);
2809 if (VectorLength2(lightcolor) < 0.01)
2812 if (rtlight->selected)
2814 f = 2 + sin(realtime * M_PI * 4.0);
2815 VectorScale(lightcolor, f, lightcolor);
2819 // loading is done before visibility checks because loading should happen
2820 // all at once at the start of a level, not when it stalls gameplay.
2821 // (especially important to benchmarks)
2822 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2823 R_RTLight_Compile(rtlight);
2824 if (rtlight->cubemapname[0])
2825 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2827 cubemaptexture = NULL;
2829 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2830 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2831 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2832 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2833 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2834 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2835 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2842 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2844 // compiled light, world available and can receive realtime lighting
2845 // retrieve cluster information
2846 numclusters = rtlight->static_numclusters;
2847 clusterlist = rtlight->static_clusterlist;
2848 clusterpvs = rtlight->static_clusterpvs;
2849 numsurfaces = rtlight->static_numsurfaces;
2850 surfacelist = rtlight->static_surfacelist;
2851 VectorCopy(rtlight->cullmins, cullmins);
2852 VectorCopy(rtlight->cullmaxs, cullmaxs);
2854 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2856 // dynamic light, world available and can receive realtime lighting
2857 // if the light box is offscreen, skip it right away
2858 if (R_CullBox(cullmins, cullmaxs))
2860 // calculate lit surfaces and clusters
2861 R_Shadow_EnlargeClusterSurfaceBuffer(r_refdef.worldmodel->brush.num_pvsclusters, r_refdef.worldmodel->nummodelsurfaces);
2862 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2863 clusterlist = r_shadow_buffer_clusterlist;
2864 clusterpvs = r_shadow_buffer_clusterpvs;
2865 surfacelist = r_shadow_buffer_surfacelist;
2867 // if the reduced cluster bounds are offscreen, skip it
2868 if (R_CullBox(cullmins, cullmaxs))
2870 // check if light is illuminating any visible clusters
2873 for (i = 0;i < numclusters;i++)
2874 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2876 if (i == numclusters)
2879 // set up a scissor rectangle for this light
2880 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2883 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2886 if (shadow && ((gl_stencil && !visiblelighting) || visiblevolumes))
2890 qglDisable(GL_CULL_FACE);
2891 GL_DepthTest(visiblevolumes < 2);
2892 GL_Color(0.0, 0.0125, 0.1, 1);
2896 R_Shadow_Stage_ShadowVolumes();
2899 ent = r_refdef.worldentity;
2900 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2902 memset(&m, 0, sizeof(m));
2903 R_Mesh_Matrix(&ent->matrix);
2904 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2906 m.pointer_vertex = mesh->vertex3f;
2908 GL_LockArrays(0, mesh->numverts);
2909 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2911 // increment stencil if backface is behind depthbuffer
2912 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2913 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2914 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2915 c_rtcached_shadowmeshes++;
2916 c_rtcached_shadowtris += mesh->numtriangles;
2917 // decrement stencil if frontface is behind depthbuffer
2918 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2919 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2921 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2922 c_rtcached_shadowmeshes++;
2923 c_rtcached_shadowtris += mesh->numtriangles;
2924 GL_LockArrays(0, 0);
2927 else if (numsurfaces)
2929 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2930 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2932 if (r_drawentities.integer)
2934 for (i = 0;i < r_refdef.numentities;i++)
2936 ent = r_refdef.entities[i];
2938 if (r_shadow_cull.integer)
2940 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2942 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2945 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2947 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2948 // light emitting entities should not cast their own shadow
2949 if (VectorLength2(relativelightorigin) < 0.1)
2951 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2952 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2953 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2954 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2955 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2956 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2957 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2962 if (visiblelighting || !visiblevolumes)
2964 if (visiblelighting)
2966 qglEnable(GL_CULL_FACE);
2967 GL_DepthTest(visiblelighting < 2);
2968 GL_Color(0.1, 0.0125, 0, 1);
2971 R_Shadow_Stage_Light(usestencil);
2973 ent = r_refdef.worldentity;
2974 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2976 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2977 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2978 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2979 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2980 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2981 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2982 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2983 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2984 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2986 R_Mesh_Matrix(&ent->matrix);
2987 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2988 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, NULL, NULL, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, visiblelighting);
2991 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist, visiblelighting);
2993 if (r_drawentities.integer)
2995 for (i = 0;i < r_refdef.numentities;i++)
2997 ent = r_refdef.entities[i];
2998 // can't draw transparent entity lighting here because
2999 // transparent meshes are deferred for later
3000 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)
3002 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
3003 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
3004 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
3005 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
3006 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
3007 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
3008 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
3009 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
3010 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, visiblelighting);
3017 void R_ShadowVolumeLighting(int visiblelighting, int visiblevolumes)
3023 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3024 R_Shadow_EditLights_Reload_f();
3026 if (visiblelighting || visiblevolumes)
3028 memset(&m, 0, sizeof(m));
3031 GL_BlendFunc(GL_ONE, GL_ONE);
3032 GL_DepthMask(false);
3033 qglCullFace(GL_FRONT); // this culls back
3036 R_Shadow_Stage_Begin();
3037 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3038 if (r_shadow_debuglight.integer >= 0)
3040 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3041 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3042 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
3045 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3046 if (light->flags & flag)
3047 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
3049 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
3050 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
3052 if (visiblelighting || visiblevolumes)
3054 qglEnable(GL_CULL_FACE);
3055 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
3058 R_Shadow_Stage_End();
3061 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3062 typedef struct suffixinfo_s
3065 qboolean flipx, flipy, flipdiagonal;
3068 static suffixinfo_t suffix[3][6] =
3071 {"px", false, false, false},
3072 {"nx", false, false, false},
3073 {"py", false, false, false},
3074 {"ny", false, false, false},
3075 {"pz", false, false, false},
3076 {"nz", false, false, false}
3079 {"posx", false, false, false},
3080 {"negx", false, false, false},
3081 {"posy", false, false, false},
3082 {"negy", false, false, false},
3083 {"posz", false, false, false},
3084 {"negz", false, false, false}
3087 {"rt", true, false, true},
3088 {"lf", false, true, true},
3089 {"ft", true, true, false},
3090 {"bk", false, false, false},
3091 {"up", true, false, true},
3092 {"dn", true, false, true}
3096 static int componentorder[4] = {0, 1, 2, 3};
3098 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3100 int i, j, cubemapsize;
3101 qbyte *cubemappixels, *image_rgba;
3102 rtexture_t *cubemaptexture;
3104 // must start 0 so the first loadimagepixels has no requested width/height
3106 cubemappixels = NULL;
3107 cubemaptexture = NULL;
3108 // keep trying different suffix groups (posx, px, rt) until one loads
3109 for (j = 0;j < 3 && !cubemappixels;j++)
3111 // load the 6 images in the suffix group
3112 for (i = 0;i < 6;i++)
3114 // generate an image name based on the base and and suffix
3115 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3117 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3119 // an image loaded, make sure width and height are equal
3120 if (image_width == image_height)
3122 // if this is the first image to load successfully, allocate the cubemap memory
3123 if (!cubemappixels && image_width >= 1)
3125 cubemapsize = image_width;
3126 // note this clears to black, so unavailable sides are black
3127 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3129 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3131 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);
3134 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3136 Mem_Free(image_rgba);
3140 // if a cubemap loaded, upload it
3143 if (!r_shadow_filters_texturepool)
3144 r_shadow_filters_texturepool = R_AllocTexturePool();
3145 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3146 Mem_Free(cubemappixels);
3150 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3151 for (j = 0;j < 3;j++)
3152 for (i = 0;i < 6;i++)
3153 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3154 Con_Print(" and was unable to find any of them.\n");
3156 return cubemaptexture;
3159 rtexture_t *R_Shadow_Cubemap(const char *basename)
3162 for (i = 0;i < numcubemaps;i++)
3163 if (!strcasecmp(cubemaps[i].basename, basename))
3164 return cubemaps[i].texture;
3165 if (i >= MAX_CUBEMAPS)
3168 strcpy(cubemaps[i].basename, basename);
3169 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3170 return cubemaps[i].texture;
3173 void R_Shadow_FreeCubemaps(void)
3176 R_FreeTexturePool(&r_shadow_filters_texturepool);
3179 dlight_t *R_Shadow_NewWorldLight(void)
3182 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3183 light->next = r_shadow_worldlightchain;
3184 r_shadow_worldlightchain = light;
3188 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)
3190 VectorCopy(origin, light->origin);
3191 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3192 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3193 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3194 light->color[0] = max(color[0], 0);
3195 light->color[1] = max(color[1], 0);
3196 light->color[2] = max(color[2], 0);
3197 light->radius = max(radius, 0);
3198 light->style = style;
3199 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3201 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3204 light->shadow = shadowenable;
3205 light->corona = corona;
3208 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3209 light->coronasizescale = coronasizescale;
3210 light->ambientscale = ambientscale;
3211 light->diffusescale = diffusescale;
3212 light->specularscale = specularscale;
3213 light->flags = flags;
3214 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3216 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3219 void R_Shadow_FreeWorldLight(dlight_t *light)
3221 dlight_t **lightpointer;
3222 R_RTLight_Uncompile(&light->rtlight);
3223 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3224 if (*lightpointer != light)
3225 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3226 *lightpointer = light->next;
3230 void R_Shadow_ClearWorldLights(void)
3232 while (r_shadow_worldlightchain)
3233 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3234 r_shadow_selectedlight = NULL;
3235 R_Shadow_FreeCubemaps();
3238 void R_Shadow_SelectLight(dlight_t *light)
3240 if (r_shadow_selectedlight)
3241 r_shadow_selectedlight->selected = false;
3242 r_shadow_selectedlight = light;
3243 if (r_shadow_selectedlight)
3244 r_shadow_selectedlight->selected = true;
3247 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3249 float scale = r_editlights_cursorgrid.value * 0.5f;
3250 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);
3253 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3256 const dlight_t *light;
3259 if (light->selected)
3260 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3263 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);
3266 void R_Shadow_DrawLightSprites(void)
3272 for (i = 0;i < 5;i++)
3274 lighttextures[i] = NULL;
3275 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3276 lighttextures[i] = pic->tex;
3279 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3280 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3281 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3284 void R_Shadow_SelectLightInView(void)
3286 float bestrating, rating, temp[3];
3287 dlight_t *best, *light;
3290 for (light = r_shadow_worldlightchain;light;light = light->next)
3292 VectorSubtract(light->origin, r_vieworigin, temp);
3293 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3296 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3297 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3299 bestrating = rating;
3304 R_Shadow_SelectLight(best);
3307 void R_Shadow_LoadWorldLights(void)
3309 int n, a, style, shadow, flags;
3310 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3311 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3312 if (r_refdef.worldmodel == NULL)
3314 Con_Print("No map loaded.\n");
3317 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3318 strlcat (name, ".rtlights", sizeof (name));
3319 lightsstring = FS_LoadFile(name, tempmempool, false);
3329 for (;COM_Parse(t, true) && strcmp(
3330 if (COM_Parse(t, true))
3332 if (com_token[0] == '!')
3335 origin[0] = atof(com_token+1);
3338 origin[0] = atof(com_token);
3343 while (*s && *s != '\n' && *s != '\r')
3349 // check for modifier flags
3356 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);
3359 flags = LIGHTFLAG_REALTIMEMODE;
3367 coronasizescale = 0.25f;
3369 VectorClear(angles);
3372 if (a < 9 || !strcmp(cubemapname, "\"\""))
3374 // remove quotes on cubemapname
3375 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3377 cubemapname[strlen(cubemapname)-1] = 0;
3378 strcpy(cubemapname, cubemapname + 1);
3382 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);
3385 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3386 radius *= r_editlights_rtlightssizescale.value;
3387 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3395 Con_Printf("invalid rtlights file \"%s\"\n", name);
3396 Mem_Free(lightsstring);
3400 void R_Shadow_SaveWorldLights(void)
3403 int bufchars, bufmaxchars;
3405 char name[MAX_QPATH];
3407 if (!r_shadow_worldlightchain)
3409 if (r_refdef.worldmodel == NULL)
3411 Con_Print("No map loaded.\n");
3414 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3415 strlcat (name, ".rtlights", sizeof (name));
3416 bufchars = bufmaxchars = 0;
3418 for (light = r_shadow_worldlightchain;light;light = light->next)
3420 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3421 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);
3422 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3423 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]);
3425 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);
3426 if (bufchars + (int) strlen(line) > bufmaxchars)
3428 bufmaxchars = bufchars + strlen(line) + 2048;
3430 buf = Mem_Alloc(tempmempool, bufmaxchars);
3434 memcpy(buf, oldbuf, bufchars);
3440 memcpy(buf + bufchars, line, strlen(line));
3441 bufchars += strlen(line);
3445 FS_WriteFile(name, buf, bufchars);
3450 void R_Shadow_LoadLightsFile(void)
3453 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3454 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3455 if (r_refdef.worldmodel == NULL)
3457 Con_Print("No map loaded.\n");
3460 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3461 strlcat (name, ".lights", sizeof (name));
3462 lightsstring = FS_LoadFile(name, tempmempool, false);
3470 while (*s && *s != '\n' && *s != '\r')
3476 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);
3480 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);
3483 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3484 radius = bound(15, radius, 4096);
3485 VectorScale(color, (2.0f / (8388608.0f)), color);
3486 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3494 Con_Printf("invalid lights file \"%s\"\n", name);
3495 Mem_Free(lightsstring);
3499 // tyrlite/hmap2 light types in the delay field
3500 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3502 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3504 int entnum, style, islight, skin, pflags, effects, type, n;
3507 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3508 char key[256], value[1024];
3510 if (r_refdef.worldmodel == NULL)
3512 Con_Print("No map loaded.\n");
3515 // try to load a .ent file first
3516 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3517 strlcat (key, ".ent", sizeof (key));
3518 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3519 // and if that is not found, fall back to the bsp file entity string
3521 data = r_refdef.worldmodel->brush.entities;
3524 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3526 type = LIGHTTYPE_MINUSX;
3527 origin[0] = origin[1] = origin[2] = 0;
3528 originhack[0] = originhack[1] = originhack[2] = 0;
3529 angles[0] = angles[1] = angles[2] = 0;
3530 color[0] = color[1] = color[2] = 1;
3531 light[0] = light[1] = light[2] = 1;light[3] = 300;
3532 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3542 if (!COM_ParseToken(&data, false))
3544 if (com_token[0] == '}')
3545 break; // end of entity
3546 if (com_token[0] == '_')
3547 strcpy(key, com_token + 1);
3549 strcpy(key, com_token);
3550 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3551 key[strlen(key)-1] = 0;
3552 if (!COM_ParseToken(&data, false))
3554 strcpy(value, com_token);
3556 // now that we have the key pair worked out...
3557 if (!strcmp("light", key))
3559 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3563 light[0] = vec[0] * (1.0f / 256.0f);
3564 light[1] = vec[0] * (1.0f / 256.0f);
3565 light[2] = vec[0] * (1.0f / 256.0f);
3571 light[0] = vec[0] * (1.0f / 255.0f);
3572 light[1] = vec[1] * (1.0f / 255.0f);
3573 light[2] = vec[2] * (1.0f / 255.0f);
3577 else if (!strcmp("delay", key))
3579 else if (!strcmp("origin", key))
3580 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3581 else if (!strcmp("angle", key))
3582 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3583 else if (!strcmp("angles", key))
3584 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3585 else if (!strcmp("color", key))
3586 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3587 else if (!strcmp("wait", key))
3588 fadescale = atof(value);
3589 else if (!strcmp("classname", key))
3591 if (!strncmp(value, "light", 5))
3594 if (!strcmp(value, "light_fluoro"))
3599 overridecolor[0] = 1;
3600 overridecolor[1] = 1;
3601 overridecolor[2] = 1;
3603 if (!strcmp(value, "light_fluorospark"))
3608 overridecolor[0] = 1;
3609 overridecolor[1] = 1;
3610 overridecolor[2] = 1;
3612 if (!strcmp(value, "light_globe"))
3617 overridecolor[0] = 1;
3618 overridecolor[1] = 0.8;
3619 overridecolor[2] = 0.4;
3621 if (!strcmp(value, "light_flame_large_yellow"))
3626 overridecolor[0] = 1;
3627 overridecolor[1] = 0.5;
3628 overridecolor[2] = 0.1;
3630 if (!strcmp(value, "light_flame_small_yellow"))
3635 overridecolor[0] = 1;
3636 overridecolor[1] = 0.5;
3637 overridecolor[2] = 0.1;
3639 if (!strcmp(value, "light_torch_small_white"))
3644 overridecolor[0] = 1;
3645 overridecolor[1] = 0.5;
3646 overridecolor[2] = 0.1;
3648 if (!strcmp(value, "light_torch_small_walltorch"))
3653 overridecolor[0] = 1;
3654 overridecolor[1] = 0.5;
3655 overridecolor[2] = 0.1;
3659 else if (!strcmp("style", key))
3660 style = atoi(value);
3661 else if (r_refdef.worldmodel->type == mod_brushq3)
3663 if (!strcmp("scale", key))
3664 lightscale = atof(value);
3665 if (!strcmp("fade", key))
3666 fadescale = atof(value);
3668 else if (!strcmp("skin", key))
3669 skin = (int)atof(value);
3670 else if (!strcmp("pflags", key))
3671 pflags = (int)atof(value);
3672 else if (!strcmp("effects", key))
3673 effects = (int)atof(value);
3677 if (lightscale <= 0)
3681 if (color[0] == color[1] && color[0] == color[2])
3683 color[0] *= overridecolor[0];
3684 color[1] *= overridecolor[1];
3685 color[2] *= overridecolor[2];
3687 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3688 color[0] = color[0] * light[0];
3689 color[1] = color[1] * light[1];
3690 color[2] = color[2] * light[2];
3693 case LIGHTTYPE_MINUSX:
3695 case LIGHTTYPE_RECIPX:
3697 VectorScale(color, (1.0f / 16.0f), color);
3699 case LIGHTTYPE_RECIPXX:
3701 VectorScale(color, (1.0f / 16.0f), color);
3704 case LIGHTTYPE_NONE:
3708 case LIGHTTYPE_MINUSXX:
3711 VectorAdd(origin, originhack, origin);
3713 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);
3716 Mem_Free(entfiledata);
3720 void R_Shadow_SetCursorLocationForView(void)
3722 vec_t dist, push, frac;
3723 vec3_t dest, endpos, normal;
3724 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3725 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3728 dist = frac * r_editlights_cursordistance.value;
3729 push = r_editlights_cursorpushback.value;
3733 VectorMA(endpos, push, r_viewforward, endpos);
3734 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3736 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3737 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3738 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3741 void R_Shadow_UpdateWorldLightSelection(void)
3743 if (r_editlights.integer)
3745 R_Shadow_SetCursorLocationForView();
3746 R_Shadow_SelectLightInView();
3747 R_Shadow_DrawLightSprites();
3750 R_Shadow_SelectLight(NULL);
3753 void R_Shadow_EditLights_Clear_f(void)
3755 R_Shadow_ClearWorldLights();
3758 void R_Shadow_EditLights_Reload_f(void)
3760 if (!r_refdef.worldmodel)
3762 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3763 R_Shadow_ClearWorldLights();
3764 R_Shadow_LoadWorldLights();
3765 if (r_shadow_worldlightchain == NULL)
3767 R_Shadow_LoadLightsFile();
3768 if (r_shadow_worldlightchain == NULL)
3769 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3773 void R_Shadow_EditLights_Save_f(void)
3775 if (!r_refdef.worldmodel)
3777 R_Shadow_SaveWorldLights();
3780 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3782 R_Shadow_ClearWorldLights();
3783 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3786 void R_Shadow_EditLights_ImportLightsFile_f(void)
3788 R_Shadow_ClearWorldLights();
3789 R_Shadow_LoadLightsFile();
3792 void R_Shadow_EditLights_Spawn_f(void)
3795 if (!r_editlights.integer)
3797 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3800 if (Cmd_Argc() != 1)
3802 Con_Print("r_editlights_spawn does not take parameters\n");
3805 color[0] = color[1] = color[2] = 1;
3806 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3809 void R_Shadow_EditLights_Edit_f(void)
3811 vec3_t origin, angles, color;
3812 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3813 int style, shadows, flags, normalmode, realtimemode;
3814 char cubemapname[1024];
3815 if (!r_editlights.integer)
3817 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3820 if (!r_shadow_selectedlight)
3822 Con_Print("No selected light.\n");
3825 VectorCopy(r_shadow_selectedlight->origin, origin);
3826 VectorCopy(r_shadow_selectedlight->angles, angles);
3827 VectorCopy(r_shadow_selectedlight->color, color);
3828 radius = r_shadow_selectedlight->radius;
3829 style = r_shadow_selectedlight->style;
3830 if (r_shadow_selectedlight->cubemapname)
3831 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3834 shadows = r_shadow_selectedlight->shadow;
3835 corona = r_shadow_selectedlight->corona;
3836 coronasizescale = r_shadow_selectedlight->coronasizescale;
3837 ambientscale = r_shadow_selectedlight->ambientscale;
3838 diffusescale = r_shadow_selectedlight->diffusescale;
3839 specularscale = r_shadow_selectedlight->specularscale;
3840 flags = r_shadow_selectedlight->flags;
3841 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3842 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3843 if (!strcmp(Cmd_Argv(1), "origin"))
3845 if (Cmd_Argc() != 5)
3847 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3850 origin[0] = atof(Cmd_Argv(2));
3851 origin[1] = atof(Cmd_Argv(3));
3852 origin[2] = atof(Cmd_Argv(4));
3854 else if (!strcmp(Cmd_Argv(1), "originx"))
3856 if (Cmd_Argc() != 3)
3858 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3861 origin[0] = atof(Cmd_Argv(2));
3863 else if (!strcmp(Cmd_Argv(1), "originy"))
3865 if (Cmd_Argc() != 3)
3867 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3870 origin[1] = atof(Cmd_Argv(2));
3872 else if (!strcmp(Cmd_Argv(1), "originz"))
3874 if (Cmd_Argc() != 3)
3876 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3879 origin[2] = atof(Cmd_Argv(2));
3881 else if (!strcmp(Cmd_Argv(1), "move"))
3883 if (Cmd_Argc() != 5)
3885 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3888 origin[0] += atof(Cmd_Argv(2));
3889 origin[1] += atof(Cmd_Argv(3));
3890 origin[2] += atof(Cmd_Argv(4));
3892 else if (!strcmp(Cmd_Argv(1), "movex"))
3894 if (Cmd_Argc() != 3)
3896 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3899 origin[0] += atof(Cmd_Argv(2));
3901 else if (!strcmp(Cmd_Argv(1), "movey"))
3903 if (Cmd_Argc() != 3)
3905 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3908 origin[1] += atof(Cmd_Argv(2));
3910 else if (!strcmp(Cmd_Argv(1), "movez"))
3912 if (Cmd_Argc() != 3)
3914 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3917 origin[2] += atof(Cmd_Argv(2));
3919 else if (!strcmp(Cmd_Argv(1), "angles"))
3921 if (Cmd_Argc() != 5)
3923 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3926 angles[0] = atof(Cmd_Argv(2));
3927 angles[1] = atof(Cmd_Argv(3));
3928 angles[2] = atof(Cmd_Argv(4));
3930 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3932 if (Cmd_Argc() != 3)
3934 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3937 angles[0] = atof(Cmd_Argv(2));
3939 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3941 if (Cmd_Argc() != 3)
3943 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3946 angles[1] = atof(Cmd_Argv(2));
3948 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3950 if (Cmd_Argc() != 3)
3952 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3955 angles[2] = atof(Cmd_Argv(2));
3957 else if (!strcmp(Cmd_Argv(1), "color"))
3959 if (Cmd_Argc() != 5)
3961 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3964 color[0] = atof(Cmd_Argv(2));
3965 color[1] = atof(Cmd_Argv(3));
3966 color[2] = atof(Cmd_Argv(4));
3968 else if (!strcmp(Cmd_Argv(1), "radius"))
3970 if (Cmd_Argc() != 3)
3972 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3975 radius = atof(Cmd_Argv(2));
3977 else if (!strcmp(Cmd_Argv(1), "style"))
3979 if (Cmd_Argc() != 3)
3981 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3984 style = atoi(Cmd_Argv(2));
3986 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3990 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3993 if (Cmd_Argc() == 3)
3994 strcpy(cubemapname, Cmd_Argv(2));
3998 else if (!strcmp(Cmd_Argv(1), "shadows"))
4000 if (Cmd_Argc() != 3)
4002 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4005 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4007 else if (!strcmp(Cmd_Argv(1), "corona"))
4009 if (Cmd_Argc() != 3)
4011 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4014 corona = atof(Cmd_Argv(2));
4016 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4018 if (Cmd_Argc() != 3)
4020 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4023 coronasizescale = atof(Cmd_Argv(2));
4025 else if (!strcmp(Cmd_Argv(1), "ambient"))
4027 if (Cmd_Argc() != 3)
4029 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4032 ambientscale = atof(Cmd_Argv(2));
4034 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4036 if (Cmd_Argc() != 3)
4038 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4041 diffusescale = atof(Cmd_Argv(2));
4043 else if (!strcmp(Cmd_Argv(1), "specular"))
4045 if (Cmd_Argc() != 3)
4047 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4050 specularscale = atof(Cmd_Argv(2));
4052 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4054 if (Cmd_Argc() != 3)
4056 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4059 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4061 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4063 if (Cmd_Argc() != 3)
4065 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4068 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4072 Con_Print("usage: r_editlights_edit [property] [value]\n");
4073 Con_Print("Selected light's properties:\n");
4074 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4075 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4076 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4077 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4078 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4079 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4080 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4081 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4082 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4083 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4084 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4085 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4086 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4087 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4090 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4091 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4094 void R_Shadow_EditLights_EditAll_f(void)
4098 if (!r_editlights.integer)
4100 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4104 for (light = r_shadow_worldlightchain;light;light = light->next)
4106 R_Shadow_SelectLight(light);
4107 R_Shadow_EditLights_Edit_f();
4111 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4113 int lightnumber, lightcount;
4117 if (!r_editlights.integer)
4123 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4124 if (light == r_shadow_selectedlight)
4125 lightnumber = lightcount;
4126 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;
4127 if (r_shadow_selectedlight == NULL)
4129 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4130 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;
4131 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;
4132 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;
4133 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4134 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4135 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4136 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;
4137 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4138 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4139 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4140 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4141 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4142 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;
4143 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;
4146 void R_Shadow_EditLights_ToggleShadow_f(void)
4148 if (!r_editlights.integer)
4150 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4153 if (!r_shadow_selectedlight)
4155 Con_Print("No selected light.\n");
4158 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);
4161 void R_Shadow_EditLights_ToggleCorona_f(void)
4163 if (!r_editlights.integer)
4165 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4168 if (!r_shadow_selectedlight)
4170 Con_Print("No selected light.\n");
4173 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);
4176 void R_Shadow_EditLights_Remove_f(void)
4178 if (!r_editlights.integer)
4180 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4183 if (!r_shadow_selectedlight)
4185 Con_Print("No selected light.\n");
4188 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4189 r_shadow_selectedlight = NULL;
4192 void R_Shadow_EditLights_Help_f(void)
4195 "Documentation on r_editlights system:\n"
4197 "r_editlights : enable/disable editing mode\n"
4198 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4199 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4200 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4201 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4202 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4203 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4204 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4206 "r_editlights_help : this help\n"
4207 "r_editlights_clear : remove all lights\n"
4208 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4209 "r_editlights_save : save to .rtlights file\n"
4210 "r_editlights_spawn : create a light with default settings\n"
4211 "r_editlights_edit command : edit selected light - more documentation below\n"
4212 "r_editlights_remove : remove selected light\n"
4213 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4214 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4215 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4217 "origin x y z : set light location\n"
4218 "originx x: set x component of light location\n"
4219 "originy y: set y component of light location\n"
4220 "originz z: set z component of light location\n"
4221 "move x y z : adjust light location\n"
4222 "movex x: adjust x component of light location\n"
4223 "movey y: adjust y component of light location\n"
4224 "movez z: adjust z component of light location\n"
4225 "angles x y z : set light angles\n"
4226 "anglesx x: set x component of light angles\n"
4227 "anglesy y: set y component of light angles\n"
4228 "anglesz z: set z component of light angles\n"
4229 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4230 "radius radius : set radius (size) of light\n"
4231 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4232 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4233 "shadows 1/0 : turn on/off shadows\n"
4234 "corona n : set corona intensity\n"
4235 "coronasize n : set corona size (0-1)\n"
4236 "ambient n : set ambient intensity (0-1)\n"
4237 "diffuse n : set diffuse intensity (0-1)\n"
4238 "specular n : set specular intensity (0-1)\n"
4239 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4240 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4241 "<nothing> : print light properties to console\n"
4245 void R_Shadow_EditLights_CopyInfo_f(void)
4247 if (!r_editlights.integer)
4249 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4252 if (!r_shadow_selectedlight)
4254 Con_Print("No selected light.\n");
4257 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4258 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4259 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4260 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4261 if (r_shadow_selectedlight->cubemapname)
4262 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4264 r_shadow_bufferlight.cubemapname[0] = 0;
4265 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4266 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4267 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4268 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4269 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4270 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4271 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4274 void R_Shadow_EditLights_PasteInfo_f(void)
4276 if (!r_editlights.integer)
4278 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4281 if (!r_shadow_selectedlight)
4283 Con_Print("No selected light.\n");
4286 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);
4289 void R_Shadow_EditLights_Init(void)
4291 Cvar_RegisterVariable(&r_editlights);
4292 Cvar_RegisterVariable(&r_editlights_cursordistance);
4293 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4294 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4295 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4296 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4297 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4298 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4299 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4300 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4301 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4302 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4303 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4304 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4305 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4306 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4307 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4308 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4309 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4310 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4311 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4312 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);