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 contains 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 typedef enum r_shadowstage_e
125 R_SHADOWSTAGE_STENCIL,
126 R_SHADOWSTAGE_STENCILTWOSIDE,
127 R_SHADOWSTAGE_LIGHT_VERTEX,
128 R_SHADOWSTAGE_LIGHT_DOT3,
129 R_SHADOWSTAGE_LIGHT_GLSL,
130 R_SHADOWSTAGE_VISIBLEVOLUMES,
131 R_SHADOWSTAGE_VISIBLELIGHTING,
135 r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
137 mempool_t *r_shadow_mempool;
139 int maxshadowelements;
153 int r_shadow_buffer_numleafpvsbytes;
154 qbyte *r_shadow_buffer_leafpvs;
155 int *r_shadow_buffer_leaflist;
157 int r_shadow_buffer_numsurfacepvsbytes;
158 qbyte *r_shadow_buffer_surfacepvs;
159 int *r_shadow_buffer_surfacelist;
161 rtexturepool_t *r_shadow_texturepool;
162 rtexture_t *r_shadow_attenuation2dtexture;
163 rtexture_t *r_shadow_attenuation3dtexture;
165 // lights are reloaded when this changes
166 char r_shadow_mapname[MAX_QPATH];
168 // used only for light filters (cubemaps)
169 rtexturepool_t *r_shadow_filters_texturepool;
171 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
172 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
173 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
174 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
175 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
176 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
177 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
178 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
179 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
180 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
181 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
182 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
183 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
184 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
185 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
186 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
187 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
188 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
189 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
190 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
191 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
192 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
193 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
194 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
195 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
196 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
197 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
198 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
199 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
200 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
201 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
202 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
203 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
204 cvar_t r_editlights = {0, "r_editlights", "0"};
205 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
206 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
207 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
208 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
209 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
210 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
211 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
213 float r_shadow_attenpower, r_shadow_attenscale;
215 rtlight_t *r_shadow_compilingrtlight;
216 dlight_t *r_shadow_worldlightchain;
217 dlight_t *r_shadow_selectedlight;
218 dlight_t r_shadow_bufferlight;
219 vec3_t r_editlights_cursorlocation;
221 rtexture_t *lighttextures[5];
223 extern int con_vislines;
225 typedef struct cubemapinfo_s
232 #define MAX_CUBEMAPS 256
233 static int numcubemaps;
234 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
236 #define SHADERPERMUTATION_SPECULAR (1<<0)
237 #define SHADERPERMUTATION_FOG (1<<1)
238 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
239 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
240 #define SHADERPERMUTATION_COUNT (1<<4)
242 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
244 void R_Shadow_UncompileWorldLights(void);
245 void R_Shadow_ClearWorldLights(void);
246 void R_Shadow_SaveWorldLights(void);
247 void R_Shadow_LoadWorldLights(void);
248 void R_Shadow_LoadLightsFile(void);
249 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
250 void R_Shadow_EditLights_Reload_f(void);
251 void R_Shadow_ValidateCvars(void);
252 static void R_Shadow_MakeTextures(void);
253 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
255 const char *builtinshader_light_vert =
256 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
257 "// written by Forest 'LordHavoc' Hale\n"
259 "uniform vec3 LightPosition;\n"
261 "varying vec2 TexCoord;\n"
262 "varying vec3 CubeVector;\n"
263 "varying vec3 LightVector;\n"
265 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
266 "uniform vec3 EyePosition;\n"
267 "varying vec3 EyeVector;\n"
270 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
274 " // copy the surface texcoord\n"
275 " TexCoord = gl_MultiTexCoord0.st;\n"
277 " // transform vertex position into light attenuation/cubemap space\n"
278 " // (-1 to +1 across the light box)\n"
279 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
281 " // transform unnormalized light direction into tangent space\n"
282 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
283 " // normalize it per pixel)\n"
284 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
285 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
286 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
287 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
289 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
290 " // transform unnormalized eye direction into tangent space\n"
291 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
292 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
293 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
294 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
297 " // transform vertex to camera space, using ftransform to match non-VS\n"
299 " gl_Position = ftransform();\n"
303 const char *builtinshader_light_frag =
304 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
305 "// written by Forest 'LordHavoc' Hale\n"
307 "uniform vec3 LightColor;\n"
309 "#ifdef USEOFFSETMAPPING\n"
310 "uniform float OffsetMapping_Scale;\n"
311 "uniform float OffsetMapping_Bias;\n"
313 "#ifdef USESPECULAR\n"
314 "uniform float SpecularPower;\n"
317 "uniform float FogRangeRecip;\n"
319 "uniform float AmbientScale;\n"
320 "uniform float DiffuseScale;\n"
321 "#ifdef USESPECULAR\n"
322 "uniform float SpecularScale;\n"
325 "uniform sampler2D Texture_Normal;\n"
326 "uniform sampler2D Texture_Color;\n"
327 "#ifdef USESPECULAR\n"
328 "uniform sampler2D Texture_Gloss;\n"
330 "#ifdef USECUBEFILTER\n"
331 "uniform samplerCube Texture_Cube;\n"
334 "uniform sampler2D Texture_FogMask;\n"
337 "varying vec2 TexCoord;\n"
338 "varying vec3 CubeVector;\n"
339 "varying vec3 LightVector;\n"
340 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
341 "varying vec3 EyeVector;\n"
348 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
349 " // center and sharp falloff at the edge, this is about the most efficient\n"
350 " // we can get away with as far as providing illumination.\n"
352 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
353 " // provide significant illumination, large = slow = pain.\n"
354 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
358 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
361 "#ifdef USEOFFSETMAPPING\n"
362 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
363 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
364 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
365 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
366 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
367 "#define TexCoord TexCoordOffset\n"
370 " // get the texels - with a blendmap we'd need to blend multiple here\n"
371 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
372 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
373 "#ifdef USESPECULAR\n"
374 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
377 " // calculate shading\n"
378 " vec3 diffusenormal = normalize(LightVector);\n"
379 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
380 "#ifdef USESPECULAR\n"
381 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
384 "#ifdef USECUBEFILTER\n"
385 " // apply light cubemap filter\n"
386 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
389 " // calculate fragment color\n"
390 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
394 void r_shadow_start(void)
397 // allocate vertex processing arrays
399 r_shadow_attenuation2dtexture = NULL;
400 r_shadow_attenuation3dtexture = NULL;
401 r_shadow_texturepool = NULL;
402 r_shadow_filters_texturepool = NULL;
403 R_Shadow_ValidateCvars();
404 R_Shadow_MakeTextures();
405 maxshadowelements = 0;
406 shadowelements = NULL;
414 shadowmarklist = NULL;
416 r_shadow_buffer_numleafpvsbytes = 0;
417 r_shadow_buffer_leafpvs = NULL;
418 r_shadow_buffer_leaflist = NULL;
419 r_shadow_buffer_numsurfacepvsbytes = 0;
420 r_shadow_buffer_surfacepvs = NULL;
421 r_shadow_buffer_surfacelist = NULL;
422 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
423 r_shadow_program_light[i] = 0;
424 if (gl_support_fragment_shader)
426 char *vertstring, *fragstring;
427 int vertstrings_count;
428 int fragstrings_count;
429 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
430 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
431 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
432 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
433 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
435 vertstrings_count = 0;
436 fragstrings_count = 0;
437 if (i & SHADERPERMUTATION_SPECULAR)
439 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
440 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
442 if (i & SHADERPERMUTATION_FOG)
444 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
445 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
447 if (i & SHADERPERMUTATION_CUBEFILTER)
449 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
450 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
452 if (i & SHADERPERMUTATION_OFFSETMAPPING)
454 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
455 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
457 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
458 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
459 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
460 if (!r_shadow_program_light[i])
462 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");
465 qglUseProgramObjectARB(r_shadow_program_light[i]);
466 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
467 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
468 if (i & SHADERPERMUTATION_SPECULAR)
470 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
472 if (i & SHADERPERMUTATION_CUBEFILTER)
474 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
476 if (i & SHADERPERMUTATION_FOG)
478 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
481 qglUseProgramObjectARB(0);
483 Mem_Free(fragstring);
485 Mem_Free(vertstring);
489 void r_shadow_shutdown(void)
492 R_Shadow_UncompileWorldLights();
493 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
495 if (r_shadow_program_light[i])
497 GL_Backend_FreeProgram(r_shadow_program_light[i]);
498 r_shadow_program_light[i] = 0;
502 r_shadow_attenuation2dtexture = NULL;
503 r_shadow_attenuation3dtexture = NULL;
504 R_FreeTexturePool(&r_shadow_texturepool);
505 R_FreeTexturePool(&r_shadow_filters_texturepool);
506 maxshadowelements = 0;
508 Mem_Free(shadowelements);
509 shadowelements = NULL;
512 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
521 Mem_Free(shadowmark);
524 Mem_Free(shadowmarklist);
525 shadowmarklist = NULL;
527 r_shadow_buffer_numleafpvsbytes = 0;
528 if (r_shadow_buffer_leafpvs)
529 Mem_Free(r_shadow_buffer_leafpvs);
530 r_shadow_buffer_leafpvs = NULL;
531 if (r_shadow_buffer_leaflist)
532 Mem_Free(r_shadow_buffer_leaflist);
533 r_shadow_buffer_leaflist = NULL;
534 r_shadow_buffer_numsurfacepvsbytes = 0;
535 if (r_shadow_buffer_surfacepvs)
536 Mem_Free(r_shadow_buffer_surfacepvs);
537 r_shadow_buffer_surfacepvs = NULL;
538 if (r_shadow_buffer_surfacelist)
539 Mem_Free(r_shadow_buffer_surfacelist);
540 r_shadow_buffer_surfacelist = NULL;
543 void r_shadow_newmap(void)
547 void R_Shadow_Help_f(void)
550 "Documentation on r_shadow system:\n"
552 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
553 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
554 "r_shadow_debuglight : render only this light number (-1 = all)\n"
555 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
556 "r_shadow_gloss2intensity : brightness of forced gloss\n"
557 "r_shadow_glossintensity : brightness of textured gloss\n"
558 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
559 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
560 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
561 "r_shadow_portallight : use portal visibility for static light precomputation\n"
562 "r_shadow_projectdistance : shadow volume projection distance\n"
563 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
564 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
565 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
566 "r_shadow_realtime_world : use high quality world lighting mode\n"
567 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
568 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
569 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
570 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
571 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
572 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
573 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
574 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
575 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
576 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
577 "r_shadow_scissor : use scissor optimization\n"
578 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
579 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
580 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
581 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
582 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
583 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
585 "r_shadow_help : this help\n"
589 void R_Shadow_Init(void)
591 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
592 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
593 Cvar_RegisterVariable(&r_shadow_debuglight);
594 Cvar_RegisterVariable(&r_shadow_gloss);
595 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
596 Cvar_RegisterVariable(&r_shadow_glossintensity);
597 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
598 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
599 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
600 Cvar_RegisterVariable(&r_shadow_portallight);
601 Cvar_RegisterVariable(&r_shadow_projectdistance);
602 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
603 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
604 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
605 Cvar_RegisterVariable(&r_shadow_realtime_world);
606 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
607 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
608 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
609 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
610 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
611 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
612 Cvar_RegisterVariable(&r_shadow_scissor);
613 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
614 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
615 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
616 Cvar_RegisterVariable(&r_shadow_texture3d);
617 Cvar_RegisterVariable(&r_shadow_visiblelighting);
618 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
619 Cvar_RegisterVariable(&r_shadow_glsl);
620 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
621 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
622 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
623 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
624 if (gamemode == GAME_TENEBRAE)
626 Cvar_SetValue("r_shadow_gloss", 2);
627 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
629 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
630 R_Shadow_EditLights_Init();
631 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
632 r_shadow_worldlightchain = NULL;
633 maxshadowelements = 0;
634 shadowelements = NULL;
642 shadowmarklist = NULL;
644 r_shadow_buffer_numleafpvsbytes = 0;
645 r_shadow_buffer_leafpvs = NULL;
646 r_shadow_buffer_leaflist = NULL;
647 r_shadow_buffer_numsurfacepvsbytes = 0;
648 r_shadow_buffer_surfacepvs = NULL;
649 r_shadow_buffer_surfacelist = NULL;
650 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
653 static matrix4x4_t matrix_attenuationxyz =
656 {0.5, 0.0, 0.0, 0.5},
657 {0.0, 0.5, 0.0, 0.5},
658 {0.0, 0.0, 0.5, 0.5},
663 static matrix4x4_t matrix_attenuationz =
666 {0.0, 0.0, 0.5, 0.5},
667 {0.0, 0.0, 0.0, 0.5},
668 {0.0, 0.0, 0.0, 0.5},
673 int *R_Shadow_ResizeShadowElements(int numtris)
675 // make sure shadowelements is big enough for this volume
676 if (maxshadowelements < numtris * 24)
678 maxshadowelements = numtris * 24;
680 Mem_Free(shadowelements);
681 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
683 return shadowelements;
686 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
688 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
689 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
690 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
692 if (r_shadow_buffer_leafpvs)
693 Mem_Free(r_shadow_buffer_leafpvs);
694 if (r_shadow_buffer_leaflist)
695 Mem_Free(r_shadow_buffer_leaflist);
696 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
697 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
698 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
700 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
702 if (r_shadow_buffer_surfacepvs)
703 Mem_Free(r_shadow_buffer_surfacepvs);
704 if (r_shadow_buffer_surfacelist)
705 Mem_Free(r_shadow_buffer_surfacelist);
706 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
707 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
708 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
712 void R_Shadow_PrepareShadowMark(int numtris)
714 // make sure shadowmark is big enough for this volume
715 if (maxshadowmark < numtris)
717 maxshadowmark = numtris;
719 Mem_Free(shadowmark);
721 Mem_Free(shadowmarklist);
722 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
723 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
727 // if shadowmarkcount wrapped we clear the array and adjust accordingly
728 if (shadowmarkcount == 0)
731 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
736 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)
739 int outtriangles = 0, outvertices = 0;
743 if (maxvertexupdate < innumvertices)
745 maxvertexupdate = innumvertices;
747 Mem_Free(vertexupdate);
749 Mem_Free(vertexremap);
750 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
751 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
755 if (vertexupdatenum == 0)
758 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
759 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
762 for (i = 0;i < numshadowmarktris;i++)
763 shadowmark[shadowmarktris[i]] = shadowmarkcount;
765 for (i = 0;i < numshadowmarktris;i++)
767 element = inelement3i + shadowmarktris[i] * 3;
768 // make sure the vertices are created
769 for (j = 0;j < 3;j++)
771 if (vertexupdate[element[j]] != vertexupdatenum)
773 float ratio, direction[3];
774 vertexupdate[element[j]] = vertexupdatenum;
775 vertexremap[element[j]] = outvertices;
776 vertex = invertex3f + element[j] * 3;
777 // project one copy of the vertex to the sphere radius of the light
778 // (FIXME: would projecting it to the light box be better?)
779 VectorSubtract(vertex, projectorigin, direction);
780 ratio = projectdistance / VectorLength(direction);
781 VectorCopy(vertex, outvertex3f);
782 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
789 for (i = 0;i < numshadowmarktris;i++)
791 int remappedelement[3];
793 const int *neighbortriangle;
795 markindex = shadowmarktris[i] * 3;
796 element = inelement3i + markindex;
797 neighbortriangle = inneighbor3i + markindex;
798 // output the front and back triangles
799 outelement3i[0] = vertexremap[element[0]];
800 outelement3i[1] = vertexremap[element[1]];
801 outelement3i[2] = vertexremap[element[2]];
802 outelement3i[3] = vertexremap[element[2]] + 1;
803 outelement3i[4] = vertexremap[element[1]] + 1;
804 outelement3i[5] = vertexremap[element[0]] + 1;
808 // output the sides (facing outward from this triangle)
809 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
811 remappedelement[0] = vertexremap[element[0]];
812 remappedelement[1] = vertexremap[element[1]];
813 outelement3i[0] = remappedelement[1];
814 outelement3i[1] = remappedelement[0];
815 outelement3i[2] = remappedelement[0] + 1;
816 outelement3i[3] = remappedelement[1];
817 outelement3i[4] = remappedelement[0] + 1;
818 outelement3i[5] = remappedelement[1] + 1;
823 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
825 remappedelement[1] = vertexremap[element[1]];
826 remappedelement[2] = vertexremap[element[2]];
827 outelement3i[0] = remappedelement[2];
828 outelement3i[1] = remappedelement[1];
829 outelement3i[2] = remappedelement[1] + 1;
830 outelement3i[3] = remappedelement[2];
831 outelement3i[4] = remappedelement[1] + 1;
832 outelement3i[5] = remappedelement[2] + 1;
837 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
839 remappedelement[0] = vertexremap[element[0]];
840 remappedelement[2] = vertexremap[element[2]];
841 outelement3i[0] = remappedelement[0];
842 outelement3i[1] = remappedelement[2];
843 outelement3i[2] = remappedelement[2] + 1;
844 outelement3i[3] = remappedelement[0];
845 outelement3i[4] = remappedelement[2] + 1;
846 outelement3i[5] = remappedelement[0] + 1;
853 *outnumvertices = outvertices;
857 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)
860 if (projectdistance < 0.1)
862 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
865 if (!numverts || !nummarktris)
867 // make sure shadowelements is big enough for this volume
868 if (maxshadowelements < nummarktris * 24)
869 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
870 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
871 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
874 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)
879 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
881 tend = firsttriangle + numtris;
882 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
883 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
884 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
886 // surface box entirely inside light box, no box cull
887 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
888 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
889 shadowmarklist[numshadowmark++] = t;
893 // surface box not entirely inside light box, cull each triangle
894 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
896 v[0] = invertex3f + e[0] * 3;
897 v[1] = invertex3f + e[1] * 3;
898 v[2] = invertex3f + e[2] * 3;
899 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
900 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
901 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
902 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
903 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
904 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
905 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
906 shadowmarklist[numshadowmark++] = t;
911 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
914 if (r_shadow_compilingrtlight)
916 // if we're compiling an rtlight, capture the mesh
917 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
920 memset(&m, 0, sizeof(m));
921 m.pointer_vertex = vertex3f;
923 GL_LockArrays(0, numvertices);
924 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
926 // increment stencil if backface is behind depthbuffer
927 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
928 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
929 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
931 c_rt_shadowtris += numtriangles;
932 // decrement stencil if frontface is behind depthbuffer
933 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
934 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
936 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
938 c_rt_shadowtris += numtriangles;
942 static void R_Shadow_MakeTextures(void)
945 float v[3], intensity;
947 R_FreeTexturePool(&r_shadow_texturepool);
948 r_shadow_texturepool = R_AllocTexturePool();
949 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
950 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
951 #define ATTEN2DSIZE 64
952 #define ATTEN3DSIZE 32
953 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
954 for (y = 0;y < ATTEN2DSIZE;y++)
956 for (x = 0;x < ATTEN2DSIZE;x++)
958 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
959 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
961 intensity = 1.0f - sqrt(DotProduct(v, v));
963 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
964 d = bound(0, intensity, 255);
965 data[(y*ATTEN2DSIZE+x)*4+0] = d;
966 data[(y*ATTEN2DSIZE+x)*4+1] = d;
967 data[(y*ATTEN2DSIZE+x)*4+2] = d;
968 data[(y*ATTEN2DSIZE+x)*4+3] = d;
971 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
972 if (r_shadow_texture3d.integer)
974 for (z = 0;z < ATTEN3DSIZE;z++)
976 for (y = 0;y < ATTEN3DSIZE;y++)
978 for (x = 0;x < ATTEN3DSIZE;x++)
980 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
981 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
982 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
983 intensity = 1.0f - sqrt(DotProduct(v, v));
985 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
986 d = bound(0, intensity, 255);
987 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
988 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
989 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
990 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
994 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
999 void R_Shadow_ValidateCvars(void)
1001 if (r_shadow_texture3d.integer && !gl_texture3d)
1002 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1003 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1004 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1007 // light currently being rendered
1008 static rtlight_t *r_shadow_rtlight;
1009 // light filter cubemap being used by the light
1010 static rtexture_t *r_shadow_lightcubemap;
1012 // this is the location of the eye in entity space
1013 static vec3_t r_shadow_entityeyeorigin;
1014 // this is the location of the light in entity space
1015 static vec3_t r_shadow_entitylightorigin;
1016 // this transforms entity coordinates to light filter cubemap coordinates
1017 // (also often used for other purposes)
1018 static matrix4x4_t r_shadow_entitytolight;
1019 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1020 // of attenuation texturing in full 3D (Z result often ignored)
1021 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1022 // this transforms only the Z to S, and T is always 0.5
1023 static matrix4x4_t r_shadow_entitytoattenuationz;
1024 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1025 static vec3_t r_shadow_entitylightcolor;
1027 static int r_shadow_lightpermutation;
1028 static int r_shadow_lightprog;
1030 void R_Shadow_Stage_Begin(void)
1034 R_Shadow_ValidateCvars();
1036 if (!r_shadow_attenuation2dtexture
1037 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1038 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1039 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1040 R_Shadow_MakeTextures();
1042 memset(&m, 0, sizeof(m));
1043 GL_BlendFunc(GL_ONE, GL_ZERO);
1044 GL_DepthMask(false);
1047 GL_Color(0, 0, 0, 1);
1048 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1049 qglEnable(GL_CULL_FACE);
1050 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1051 r_shadowstage = R_SHADOWSTAGE_NONE;
1054 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1056 r_shadow_rtlight = rtlight;
1059 void R_Shadow_Stage_Reset(void)
1062 if (gl_support_stenciltwoside)
1063 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1064 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1066 qglUseProgramObjectARB(0);
1067 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1068 qglBegin(GL_TRIANGLES);
1072 memset(&m, 0, sizeof(m));
1076 void R_Shadow_Stage_StencilShadowVolumes(void)
1078 R_Shadow_Stage_Reset();
1079 GL_Color(1, 1, 1, 1);
1080 GL_ColorMask(0, 0, 0, 0);
1081 GL_BlendFunc(GL_ONE, GL_ZERO);
1082 GL_DepthMask(false);
1084 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1085 //if (r_shadow_shadow_polygonoffset.value != 0)
1087 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1088 // qglEnable(GL_POLYGON_OFFSET_FILL);
1091 // qglDisable(GL_POLYGON_OFFSET_FILL);
1092 qglDepthFunc(GL_GEQUAL);
1093 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1094 qglEnable(GL_STENCIL_TEST);
1095 qglStencilFunc(GL_ALWAYS, 128, ~0);
1096 if (gl_ext_stenciltwoside.integer)
1098 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1099 qglDisable(GL_CULL_FACE);
1100 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1101 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1103 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
1104 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1106 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1110 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1111 qglEnable(GL_CULL_FACE);
1113 // this is changed by every shadow render so its value here is unimportant
1114 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1116 GL_Clear(GL_STENCIL_BUFFER_BIT);
1120 void R_Shadow_Stage_Lighting(int stenciltest)
1123 R_Shadow_Stage_Reset();
1124 GL_BlendFunc(GL_ONE, GL_ONE);
1125 GL_DepthMask(false);
1127 qglPolygonOffset(0, 0);
1128 //qglDisable(GL_POLYGON_OFFSET_FILL);
1129 GL_Color(1, 1, 1, 1);
1130 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1131 qglDepthFunc(GL_EQUAL);
1132 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1133 qglEnable(GL_CULL_FACE);
1134 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1135 qglEnable(GL_STENCIL_TEST);
1137 qglDisable(GL_STENCIL_TEST);
1139 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1140 // only draw light where this geometry was already rendered AND the
1141 // stencil is 128 (values other than this mean shadow)
1142 qglStencilFunc(GL_EQUAL, 128, ~0);
1143 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1145 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1146 memset(&m, 0, sizeof(m));
1147 m.pointer_vertex = varray_vertex3f;
1148 m.pointer_texcoord[0] = varray_texcoord2f[0];
1149 m.pointer_texcoord3f[1] = varray_svector3f;
1150 m.pointer_texcoord3f[2] = varray_tvector3f;
1151 m.pointer_texcoord3f[3] = varray_normal3f;
1152 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1153 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1154 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1155 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1156 // TODO: support fog (after renderer is converted to texture fog)
1157 m.tex[4] = R_GetTexture(r_texture_white); // fog
1158 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1160 GL_BlendFunc(GL_ONE, GL_ONE);
1161 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1163 r_shadow_lightpermutation = 0;
1164 // only add a feature to the permutation if that permutation exists
1165 // (otherwise it might end up not using a shader at all, which looks
1166 // worse than using less features)
1167 if (r_shadow_rtlight->specularscale && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1168 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1169 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1170 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1171 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1172 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1173 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1174 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1175 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1176 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1177 // TODO: support fog (after renderer is converted to texture fog)
1178 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1180 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1182 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1183 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1184 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1186 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1187 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1189 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1190 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1191 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1193 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1195 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1197 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1198 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1201 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1202 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1204 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1207 void R_Shadow_Stage_VisibleShadowVolumes(void)
1209 R_Shadow_Stage_Reset();
1210 GL_BlendFunc(GL_ONE, GL_ONE);
1211 GL_DepthMask(false);
1212 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1213 qglPolygonOffset(0, 0);
1214 GL_Color(0.0, 0.0125, 0.1, 1);
1215 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1216 qglDepthFunc(GL_GEQUAL);
1217 qglCullFace(GL_FRONT); // this culls back
1218 qglDisable(GL_CULL_FACE);
1219 qglDisable(GL_STENCIL_TEST);
1220 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1223 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1225 R_Shadow_Stage_Reset();
1226 GL_BlendFunc(GL_ONE, GL_ONE);
1227 GL_DepthMask(false);
1228 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1229 qglPolygonOffset(0, 0);
1230 GL_Color(0.1, 0.0125, 0, 1);
1231 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1232 qglDepthFunc(GL_EQUAL);
1233 qglCullFace(GL_FRONT); // this culls back
1234 qglEnable(GL_CULL_FACE);
1236 qglEnable(GL_STENCIL_TEST);
1238 qglDisable(GL_STENCIL_TEST);
1239 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1242 void R_Shadow_Stage_End(void)
1244 R_Shadow_Stage_Reset();
1245 R_Shadow_Stage_ActiveLight(NULL);
1246 GL_BlendFunc(GL_ONE, GL_ZERO);
1249 qglPolygonOffset(0, 0);
1250 //qglDisable(GL_POLYGON_OFFSET_FILL);
1251 GL_Color(1, 1, 1, 1);
1252 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1253 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1254 qglDepthFunc(GL_LEQUAL);
1255 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1256 qglDisable(GL_STENCIL_TEST);
1257 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1258 if (gl_support_stenciltwoside)
1259 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1261 qglStencilFunc(GL_ALWAYS, 128, ~0);
1262 r_shadowstage = R_SHADOWSTAGE_NONE;
1265 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1267 int i, ix1, iy1, ix2, iy2;
1268 float x1, y1, x2, y2, x, y, f;
1269 vec3_t smins, smaxs;
1271 if (!r_shadow_scissor.integer)
1273 // if view is inside the box, just say yes it's visible
1274 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1276 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1279 for (i = 0;i < 3;i++)
1281 if (r_viewforward[i] >= 0)
1292 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1293 if (DotProduct(r_viewforward, v2) <= f)
1295 // entirely behind nearclip plane
1298 if (DotProduct(r_viewforward, v) >= f)
1300 // entirely infront of nearclip plane
1301 x1 = y1 = x2 = y2 = 0;
1302 for (i = 0;i < 8;i++)
1304 v[0] = (i & 1) ? mins[0] : maxs[0];
1305 v[1] = (i & 2) ? mins[1] : maxs[1];
1306 v[2] = (i & 4) ? mins[2] : maxs[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]);
1328 // clipped by nearclip plane
1329 // this is nasty and crude...
1330 // create viewspace bbox
1331 for (i = 0;i < 8;i++)
1333 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1334 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1335 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1336 v2[0] = -DotProduct(v, r_viewleft);
1337 v2[1] = DotProduct(v, r_viewup);
1338 v2[2] = DotProduct(v, r_viewforward);
1341 if (smins[0] > v2[0]) smins[0] = v2[0];
1342 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1343 if (smins[1] > v2[1]) smins[1] = v2[1];
1344 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1345 if (smins[2] > v2[2]) smins[2] = v2[2];
1346 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1350 smins[0] = smaxs[0] = v2[0];
1351 smins[1] = smaxs[1] = v2[1];
1352 smins[2] = smaxs[2] = v2[2];
1355 // now we have a bbox in viewspace
1356 // clip it to the view plane
1359 // return true if that culled the box
1360 if (smins[2] >= smaxs[2])
1362 // ok some of it is infront of the view, transform each corner back to
1363 // worldspace and then to screenspace and make screen rect
1364 // initialize these variables just to avoid compiler warnings
1365 x1 = y1 = x2 = y2 = 0;
1366 for (i = 0;i < 8;i++)
1368 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1369 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1370 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1371 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1372 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1373 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1375 GL_TransformToScreen(v, v2);
1376 //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]);
1393 // this code doesn't handle boxes with any points behind view properly
1394 x1 = 1000;x2 = -1000;
1395 y1 = 1000;y2 = -1000;
1396 for (i = 0;i < 8;i++)
1398 v[0] = (i & 1) ? mins[0] : maxs[0];
1399 v[1] = (i & 2) ? mins[1] : maxs[1];
1400 v[2] = (i & 4) ? mins[2] : maxs[2];
1402 GL_TransformToScreen(v, v2);
1403 //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]);
1421 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1422 if (ix1 < r_view_x) ix1 = r_view_x;
1423 if (iy1 < r_view_y) iy1 = r_view_y;
1424 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1425 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1426 if (ix2 <= ix1 || iy2 <= iy1)
1428 // set up the scissor rectangle
1429 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1430 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1431 //qglEnable(GL_SCISSOR_TEST);
1436 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1438 float *color4f = varray_color4f;
1439 float dist, dot, intensity, v[3], n[3];
1440 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1442 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1443 if ((dist = DotProduct(v, v)) < 1)
1445 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1446 if ((dot = DotProduct(n, v)) > 0)
1449 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1450 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1451 VectorScale(lightcolor, intensity, color4f);
1456 VectorClear(color4f);
1462 VectorClear(color4f);
1468 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1470 float *color4f = varray_color4f;
1471 float dist, dot, intensity, v[3], n[3];
1472 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1474 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1475 if ((dist = fabs(v[2])) < 1)
1477 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1478 if ((dot = DotProduct(n, v)) > 0)
1480 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1481 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1482 VectorScale(lightcolor, intensity, color4f);
1487 VectorClear(color4f);
1493 VectorClear(color4f);
1499 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1501 float *color4f = varray_color4f;
1502 float dot, intensity, v[3], n[3];
1503 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1505 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1506 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1507 if ((dot = DotProduct(n, v)) > 0)
1509 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1510 VectorScale(lightcolor, intensity, color4f);
1515 VectorClear(color4f);
1521 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1523 float *color4f = varray_color4f;
1524 float dist, intensity, v[3];
1525 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1527 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1528 if ((dist = DotProduct(v, v)) < 1)
1531 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1532 VectorScale(lightcolor, intensity, color4f);
1537 VectorClear(color4f);
1543 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1545 float *color4f = varray_color4f;
1546 float dist, intensity, v[3];
1547 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1549 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1550 if ((dist = fabs(v[2])) < 1)
1552 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1553 VectorScale(lightcolor, intensity, color4f);
1558 VectorClear(color4f);
1564 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1565 #define USETEXMATRIX
1567 #ifndef USETEXMATRIX
1568 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1569 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1570 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1574 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1575 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1576 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1583 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1587 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1588 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1596 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)
1600 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1602 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1603 // the cubemap normalizes this for us
1604 out3f[0] = DotProduct(svector3f, lightdir);
1605 out3f[1] = DotProduct(tvector3f, lightdir);
1606 out3f[2] = DotProduct(normal3f, lightdir);
1610 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)
1613 float lightdir[3], eyedir[3], halfdir[3];
1614 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1616 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1617 VectorNormalizeFast(lightdir);
1618 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1619 VectorNormalizeFast(eyedir);
1620 VectorAdd(lightdir, eyedir, halfdir);
1621 // the cubemap normalizes this for us
1622 out3f[0] = DotProduct(svector3f, halfdir);
1623 out3f[1] = DotProduct(tvector3f, halfdir);
1624 out3f[2] = DotProduct(normal3f, halfdir);
1628 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 *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture)
1631 float color[3], color2[3], colorscale, specularscale;
1633 // FIXME: support EF_NODEPTHTEST
1635 basetexture = r_texture_white;
1637 bumptexture = r_texture_blanknormalmap;
1639 lightcolorpants = vec3_origin;
1641 lightcolorshirt = vec3_origin;
1642 if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1643 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
1644 else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1646 glosstexture = r_texture_white;
1647 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
1651 glosstexture = r_texture_black;
1654 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1656 if (r_shadowstage == R_SHADOWSTAGE_VISIBLELIGHTING)
1659 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1660 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1661 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1663 // TODO: add direct pants/shirt rendering
1664 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1665 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1666 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1667 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1668 if (r_shadow_rtlight->ambientscale)
1670 colorscale = r_shadow_rtlight->ambientscale;
1671 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1674 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1677 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1680 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1685 VectorScale(lightcolorbase, colorscale, color2);
1686 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1689 if (r_shadow_rtlight->diffusescale)
1691 colorscale = r_shadow_rtlight->diffusescale;
1692 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1694 // 3/2 3D combine path (Geforce3, Radeon 8500)
1697 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1699 // 1/2/2 3D combine path (original Radeon)
1702 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1704 // 2/2 3D combine path (original Radeon)
1707 else if (r_textureunits.integer >= 4)
1709 // 4/2 2D combine path (Geforce3, Radeon 8500)
1714 // 2/2/2 2D combine path (any dot3 card)
1717 VectorScale(lightcolorbase, colorscale, color2);
1718 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1721 if (specularscale && glosstexture != r_texture_black)
1723 //if (gl_support_blendsquare)
1725 colorscale = specularscale;
1726 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1728 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1732 VectorScale(lightcolorbase, colorscale, color2);
1733 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1740 // TODO: add direct pants/shirt rendering
1741 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1742 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1743 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1744 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1745 if (r_shadow_rtlight->ambientscale)
1747 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
1748 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1751 if (r_shadow_rtlight->diffusescale)
1753 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
1754 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1760 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1761 memset(&m, 0, sizeof(m));
1762 m.pointer_vertex = vertex3f;
1764 GL_LockArrays(firstvertex, numvertices);
1765 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1766 GL_LockArrays(0, 0);
1770 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1772 // GLSL shader path (GFFX5200, Radeon 9500)
1773 R_Mesh_VertexPointer(vertex3f);
1774 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1775 R_Mesh_TexCoordPointer(1, 3, svector3f);
1776 R_Mesh_TexCoordPointer(2, 3, tvector3f);
1777 R_Mesh_TexCoordPointer(3, 3, normal3f);
1778 R_Mesh_TexBind(0, R_GetTexture(bumptexture));
1779 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1780 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1781 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1783 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1785 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1786 GL_LockArrays(firstvertex, numvertices);
1787 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1789 c_rt_lighttris += numtriangles;
1790 // TODO: add direct pants/shirt rendering
1791 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1793 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1794 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1795 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1797 c_rt_lighttris += numtriangles;
1799 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1801 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1802 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1803 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1805 c_rt_lighttris += numtriangles;
1807 GL_LockArrays(0, 0);
1809 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
1811 // TODO: add direct pants/shirt rendering
1812 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1813 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1814 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1815 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1816 if (r_shadow_rtlight->ambientscale)
1819 colorscale = r_shadow_rtlight->ambientscale;
1820 // colorscale accounts for how much we multiply the brightness
1823 // mult is how many times the final pass of the lighting will be
1824 // performed to get more brightness than otherwise possible.
1826 // Limit mult to 64 for sanity sake.
1827 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1829 // 3 3D combine path (Geforce3, Radeon 8500)
1830 memset(&m, 0, sizeof(m));
1831 m.pointer_vertex = vertex3f;
1832 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1834 m.pointer_texcoord3f[0] = vertex3f;
1835 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1837 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1838 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1840 m.tex[1] = R_GetTexture(basetexture);
1841 m.pointer_texcoord[1] = texcoord2f;
1842 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1844 m.pointer_texcoord3f[2] = vertex3f;
1845 m.texmatrix[2] = r_shadow_entitytolight;
1847 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1848 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1850 GL_BlendFunc(GL_ONE, GL_ONE);
1852 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1854 // 2 3D combine path (Geforce3, original Radeon)
1855 memset(&m, 0, sizeof(m));
1856 m.pointer_vertex = vertex3f;
1857 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1859 m.pointer_texcoord3f[0] = vertex3f;
1860 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1862 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1863 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1865 m.tex[1] = R_GetTexture(basetexture);
1866 m.pointer_texcoord[1] = texcoord2f;
1867 GL_BlendFunc(GL_ONE, GL_ONE);
1869 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1871 // 4 2D combine path (Geforce3, Radeon 8500)
1872 memset(&m, 0, sizeof(m));
1873 m.pointer_vertex = vertex3f;
1874 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1876 m.pointer_texcoord3f[0] = vertex3f;
1877 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1879 m.pointer_texcoord[0] = varray_texcoord2f[0];
1880 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1882 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1884 m.pointer_texcoord3f[1] = vertex3f;
1885 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1887 m.pointer_texcoord[1] = varray_texcoord2f[1];
1888 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1890 m.tex[2] = R_GetTexture(basetexture);
1891 m.pointer_texcoord[2] = texcoord2f;
1892 if (r_shadow_lightcubemap != r_texture_whitecube)
1894 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1896 m.pointer_texcoord3f[3] = vertex3f;
1897 m.texmatrix[3] = r_shadow_entitytolight;
1899 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1900 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1903 GL_BlendFunc(GL_ONE, GL_ONE);
1905 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1907 // 3 2D combine path (Geforce3, original Radeon)
1908 memset(&m, 0, sizeof(m));
1909 m.pointer_vertex = vertex3f;
1910 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1912 m.pointer_texcoord3f[0] = vertex3f;
1913 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1915 m.pointer_texcoord[0] = varray_texcoord2f[0];
1916 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1918 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1920 m.pointer_texcoord3f[1] = vertex3f;
1921 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1923 m.pointer_texcoord[1] = varray_texcoord2f[1];
1924 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1926 m.tex[2] = R_GetTexture(basetexture);
1927 m.pointer_texcoord[2] = texcoord2f;
1928 GL_BlendFunc(GL_ONE, GL_ONE);
1932 // 2/2/2 2D combine path (any dot3 card)
1933 memset(&m, 0, sizeof(m));
1934 m.pointer_vertex = vertex3f;
1935 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1937 m.pointer_texcoord3f[0] = vertex3f;
1938 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1940 m.pointer_texcoord[0] = varray_texcoord2f[0];
1941 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1943 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1945 m.pointer_texcoord3f[1] = vertex3f;
1946 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1948 m.pointer_texcoord[1] = varray_texcoord2f[1];
1949 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1952 GL_ColorMask(0,0,0,1);
1953 GL_BlendFunc(GL_ONE, GL_ZERO);
1954 GL_LockArrays(firstvertex, numvertices);
1955 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1956 GL_LockArrays(0, 0);
1958 c_rt_lighttris += numtriangles;
1960 memset(&m, 0, sizeof(m));
1961 m.pointer_vertex = vertex3f;
1962 m.tex[0] = R_GetTexture(basetexture);
1963 m.pointer_texcoord[0] = texcoord2f;
1964 if (r_shadow_lightcubemap != r_texture_whitecube)
1966 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1968 m.pointer_texcoord3f[1] = vertex3f;
1969 m.texmatrix[1] = r_shadow_entitytolight;
1971 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1972 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1975 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1977 // this final code is shared
1979 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1980 VectorScale(lightcolorbase, colorscale, color2);
1981 GL_LockArrays(firstvertex, numvertices);
1982 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1984 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1985 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1987 c_rt_lighttris += numtriangles;
1989 GL_LockArrays(0, 0);
1991 if (r_shadow_rtlight->diffusescale)
1994 colorscale = r_shadow_rtlight->diffusescale;
1995 // colorscale accounts for how much we multiply the brightness
1998 // mult is how many times the final pass of the lighting will be
1999 // performed to get more brightness than otherwise possible.
2001 // Limit mult to 64 for sanity sake.
2002 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2004 // 3/2 3D combine path (Geforce3, Radeon 8500)
2005 memset(&m, 0, sizeof(m));
2006 m.pointer_vertex = vertex3f;
2007 m.tex[0] = R_GetTexture(bumptexture);
2008 m.texcombinergb[0] = GL_REPLACE;
2009 m.pointer_texcoord[0] = texcoord2f;
2010 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2011 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2012 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2013 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2014 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2016 m.pointer_texcoord3f[2] = vertex3f;
2017 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2019 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
2020 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2023 GL_ColorMask(0,0,0,1);
2024 GL_BlendFunc(GL_ONE, GL_ZERO);
2025 GL_LockArrays(firstvertex, numvertices);
2026 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2027 GL_LockArrays(0, 0);
2029 c_rt_lighttris += numtriangles;
2031 memset(&m, 0, sizeof(m));
2032 m.pointer_vertex = vertex3f;
2033 m.tex[0] = R_GetTexture(basetexture);
2034 m.pointer_texcoord[0] = texcoord2f;
2035 if (r_shadow_lightcubemap != r_texture_whitecube)
2037 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2039 m.pointer_texcoord3f[1] = vertex3f;
2040 m.texmatrix[1] = r_shadow_entitytolight;
2042 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2043 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2046 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2048 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
2050 // 1/2/2 3D combine path (original Radeon)
2051 memset(&m, 0, sizeof(m));
2052 m.pointer_vertex = vertex3f;
2053 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2055 m.pointer_texcoord3f[0] = vertex3f;
2056 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2058 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2059 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2062 GL_ColorMask(0,0,0,1);
2063 GL_BlendFunc(GL_ONE, GL_ZERO);
2064 GL_LockArrays(firstvertex, numvertices);
2065 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2066 GL_LockArrays(0, 0);
2068 c_rt_lighttris += numtriangles;
2070 memset(&m, 0, sizeof(m));
2071 m.pointer_vertex = vertex3f;
2072 m.tex[0] = R_GetTexture(bumptexture);
2073 m.texcombinergb[0] = GL_REPLACE;
2074 m.pointer_texcoord[0] = texcoord2f;
2075 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2076 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2077 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2078 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2080 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2081 GL_LockArrays(firstvertex, numvertices);
2082 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2083 GL_LockArrays(0, 0);
2085 c_rt_lighttris += numtriangles;
2087 memset(&m, 0, sizeof(m));
2088 m.pointer_vertex = vertex3f;
2089 m.tex[0] = R_GetTexture(basetexture);
2090 m.pointer_texcoord[0] = texcoord2f;
2091 if (r_shadow_lightcubemap != r_texture_whitecube)
2093 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2095 m.pointer_texcoord3f[1] = vertex3f;
2096 m.texmatrix[1] = r_shadow_entitytolight;
2098 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2099 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2102 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2104 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2106 // 2/2 3D combine path (original Radeon)
2107 memset(&m, 0, sizeof(m));
2108 m.pointer_vertex = vertex3f;
2109 m.tex[0] = R_GetTexture(bumptexture);
2110 m.texcombinergb[0] = GL_REPLACE;
2111 m.pointer_texcoord[0] = texcoord2f;
2112 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2113 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2114 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2115 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2117 GL_ColorMask(0,0,0,1);
2118 GL_BlendFunc(GL_ONE, GL_ZERO);
2119 GL_LockArrays(firstvertex, numvertices);
2120 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2121 GL_LockArrays(0, 0);
2123 c_rt_lighttris += numtriangles;
2125 memset(&m, 0, sizeof(m));
2126 m.pointer_vertex = vertex3f;
2127 m.tex[0] = R_GetTexture(basetexture);
2128 m.pointer_texcoord[0] = texcoord2f;
2129 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2131 m.pointer_texcoord3f[1] = vertex3f;
2132 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2134 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2135 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2137 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2139 else if (r_textureunits.integer >= 4)
2141 // 4/2 2D combine path (Geforce3, Radeon 8500)
2142 memset(&m, 0, sizeof(m));
2143 m.pointer_vertex = vertex3f;
2144 m.tex[0] = R_GetTexture(bumptexture);
2145 m.texcombinergb[0] = GL_REPLACE;
2146 m.pointer_texcoord[0] = texcoord2f;
2147 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2148 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2149 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2150 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2151 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2153 m.pointer_texcoord3f[2] = vertex3f;
2154 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2156 m.pointer_texcoord[2] = varray_texcoord2f[2];
2157 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2159 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2161 m.pointer_texcoord3f[3] = vertex3f;
2162 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2164 m.pointer_texcoord[3] = varray_texcoord2f[3];
2165 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2168 GL_ColorMask(0,0,0,1);
2169 GL_BlendFunc(GL_ONE, GL_ZERO);
2170 GL_LockArrays(firstvertex, numvertices);
2171 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2172 GL_LockArrays(0, 0);
2174 c_rt_lighttris += numtriangles;
2176 memset(&m, 0, sizeof(m));
2177 m.pointer_vertex = vertex3f;
2178 m.tex[0] = R_GetTexture(basetexture);
2179 m.pointer_texcoord[0] = texcoord2f;
2180 if (r_shadow_lightcubemap != r_texture_whitecube)
2182 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2184 m.pointer_texcoord3f[1] = vertex3f;
2185 m.texmatrix[1] = r_shadow_entitytolight;
2187 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2188 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2191 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2195 // 2/2/2 2D combine path (any dot3 card)
2196 memset(&m, 0, sizeof(m));
2197 m.pointer_vertex = vertex3f;
2198 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2200 m.pointer_texcoord3f[0] = vertex3f;
2201 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2203 m.pointer_texcoord[0] = varray_texcoord2f[0];
2204 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2206 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2208 m.pointer_texcoord3f[1] = vertex3f;
2209 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2211 m.pointer_texcoord[1] = varray_texcoord2f[1];
2212 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2215 GL_ColorMask(0,0,0,1);
2216 GL_BlendFunc(GL_ONE, GL_ZERO);
2217 GL_LockArrays(firstvertex, numvertices);
2218 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2219 GL_LockArrays(0, 0);
2221 c_rt_lighttris += numtriangles;
2223 memset(&m, 0, sizeof(m));
2224 m.pointer_vertex = vertex3f;
2225 m.tex[0] = R_GetTexture(bumptexture);
2226 m.texcombinergb[0] = GL_REPLACE;
2227 m.pointer_texcoord[0] = texcoord2f;
2228 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2229 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2230 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2231 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
2233 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2234 GL_LockArrays(firstvertex, numvertices);
2235 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2236 GL_LockArrays(0, 0);
2238 c_rt_lighttris += numtriangles;
2240 memset(&m, 0, sizeof(m));
2241 m.pointer_vertex = vertex3f;
2242 m.tex[0] = R_GetTexture(basetexture);
2243 m.pointer_texcoord[0] = texcoord2f;
2244 if (r_shadow_lightcubemap != r_texture_whitecube)
2246 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2248 m.pointer_texcoord3f[1] = vertex3f;
2249 m.texmatrix[1] = r_shadow_entitytolight;
2251 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2252 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2255 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2257 // this final code is shared
2259 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2260 VectorScale(lightcolorbase, colorscale, color2);
2261 GL_LockArrays(firstvertex, numvertices);
2262 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2264 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2265 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2267 c_rt_lighttris += numtriangles;
2269 GL_LockArrays(0, 0);
2271 if (specularscale && glosstexture != r_texture_black)
2273 // FIXME: detect blendsquare!
2274 //if (gl_support_blendsquare)
2276 colorscale = specularscale;
2278 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2280 // 2/0/0/1/2 3D combine blendsquare path
2281 memset(&m, 0, sizeof(m));
2282 m.pointer_vertex = vertex3f;
2283 m.tex[0] = R_GetTexture(bumptexture);
2284 m.pointer_texcoord[0] = texcoord2f;
2285 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2286 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2287 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2288 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2290 GL_ColorMask(0,0,0,1);
2291 // this squares the result
2292 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2293 GL_LockArrays(firstvertex, numvertices);
2294 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2295 GL_LockArrays(0, 0);
2297 c_rt_lighttris += numtriangles;
2299 memset(&m, 0, sizeof(m));
2300 m.pointer_vertex = vertex3f;
2302 GL_LockArrays(firstvertex, numvertices);
2303 // square alpha in framebuffer a few times to make it shiny
2304 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2305 // these comments are a test run through this math for intensity 0.5
2306 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2307 // 0.25 * 0.25 = 0.0625 (this is another pass)
2308 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2309 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2311 c_rt_lighttris += numtriangles;
2312 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2314 c_rt_lighttris += numtriangles;
2315 GL_LockArrays(0, 0);
2317 memset(&m, 0, sizeof(m));
2318 m.pointer_vertex = vertex3f;
2319 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2321 m.pointer_texcoord3f[0] = vertex3f;
2322 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2324 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2325 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2328 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2329 GL_LockArrays(firstvertex, numvertices);
2330 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2331 GL_LockArrays(0, 0);
2333 c_rt_lighttris += numtriangles;
2335 memset(&m, 0, sizeof(m));
2336 m.pointer_vertex = vertex3f;
2337 m.tex[0] = R_GetTexture(glosstexture);
2338 m.pointer_texcoord[0] = texcoord2f;
2339 if (r_shadow_lightcubemap != r_texture_whitecube)
2341 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2343 m.pointer_texcoord3f[1] = vertex3f;
2344 m.texmatrix[1] = r_shadow_entitytolight;
2346 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2347 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2350 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2352 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2354 // 2/0/0/2 3D combine blendsquare path
2355 memset(&m, 0, sizeof(m));
2356 m.pointer_vertex = vertex3f;
2357 m.tex[0] = R_GetTexture(bumptexture);
2358 m.pointer_texcoord[0] = texcoord2f;
2359 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2360 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2361 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2362 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2364 GL_ColorMask(0,0,0,1);
2365 // this squares the result
2366 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2367 GL_LockArrays(firstvertex, numvertices);
2368 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2369 GL_LockArrays(0, 0);
2371 c_rt_lighttris += numtriangles;
2373 memset(&m, 0, sizeof(m));
2374 m.pointer_vertex = vertex3f;
2376 GL_LockArrays(firstvertex, numvertices);
2377 // square alpha in framebuffer a few times to make it shiny
2378 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2379 // these comments are a test run through this math for intensity 0.5
2380 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2381 // 0.25 * 0.25 = 0.0625 (this is another pass)
2382 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2383 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2385 c_rt_lighttris += numtriangles;
2386 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2388 c_rt_lighttris += numtriangles;
2389 GL_LockArrays(0, 0);
2391 memset(&m, 0, sizeof(m));
2392 m.pointer_vertex = vertex3f;
2393 m.tex[0] = R_GetTexture(glosstexture);
2394 m.pointer_texcoord[0] = texcoord2f;
2395 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2397 m.pointer_texcoord3f[1] = vertex3f;
2398 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2400 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2401 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2403 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2407 // 2/0/0/2/2 2D combine blendsquare path
2408 memset(&m, 0, sizeof(m));
2409 m.pointer_vertex = vertex3f;
2410 m.tex[0] = R_GetTexture(bumptexture);
2411 m.pointer_texcoord[0] = texcoord2f;
2412 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2413 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2414 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2415 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2417 GL_ColorMask(0,0,0,1);
2418 // this squares the result
2419 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2420 GL_LockArrays(firstvertex, numvertices);
2421 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2422 GL_LockArrays(0, 0);
2424 c_rt_lighttris += numtriangles;
2426 memset(&m, 0, sizeof(m));
2427 m.pointer_vertex = vertex3f;
2429 GL_LockArrays(firstvertex, numvertices);
2430 // square alpha in framebuffer a few times to make it shiny
2431 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2432 // these comments are a test run through this math for intensity 0.5
2433 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2434 // 0.25 * 0.25 = 0.0625 (this is another pass)
2435 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2436 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2438 c_rt_lighttris += numtriangles;
2439 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2441 c_rt_lighttris += numtriangles;
2442 GL_LockArrays(0, 0);
2444 memset(&m, 0, sizeof(m));
2445 m.pointer_vertex = vertex3f;
2446 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2448 m.pointer_texcoord3f[0] = vertex3f;
2449 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2451 m.pointer_texcoord[0] = varray_texcoord2f[0];
2452 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2454 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2456 m.pointer_texcoord3f[1] = vertex3f;
2457 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2459 m.pointer_texcoord[1] = varray_texcoord2f[1];
2460 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2463 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2464 GL_LockArrays(firstvertex, numvertices);
2465 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2466 GL_LockArrays(0, 0);
2468 c_rt_lighttris += numtriangles;
2470 memset(&m, 0, sizeof(m));
2471 m.pointer_vertex = vertex3f;
2472 m.tex[0] = R_GetTexture(glosstexture);
2473 m.pointer_texcoord[0] = texcoord2f;
2474 if (r_shadow_lightcubemap != r_texture_whitecube)
2476 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2478 m.pointer_texcoord3f[1] = vertex3f;
2479 m.texmatrix[1] = r_shadow_entitytolight;
2481 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2482 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2485 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2488 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2489 VectorScale(lightcolorbase, colorscale, color2);
2490 GL_LockArrays(firstvertex, numvertices);
2491 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2493 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2494 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2496 c_rt_lighttris += numtriangles;
2498 GL_LockArrays(0, 0);
2502 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
2504 // TODO: add direct pants/shirt rendering
2505 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2506 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
2507 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2508 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
2509 if (r_shadow_rtlight->ambientscale)
2511 GL_BlendFunc(GL_ONE, GL_ONE);
2512 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
2513 memset(&m, 0, sizeof(m));
2514 m.pointer_vertex = vertex3f;
2515 m.tex[0] = R_GetTexture(basetexture);
2516 m.pointer_texcoord[0] = texcoord2f;
2517 if (r_textureunits.integer >= 2)
2520 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2522 m.pointer_texcoord3f[1] = vertex3f;
2523 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2525 m.pointer_texcoord[1] = varray_texcoord2f[1];
2526 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2528 if (r_textureunits.integer >= 3)
2530 // Geforce3/Radeon class but not using dot3
2531 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2533 m.pointer_texcoord3f[2] = vertex3f;
2534 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2536 m.pointer_texcoord[2] = varray_texcoord2f[2];
2537 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2541 if (r_textureunits.integer >= 3)
2542 m.pointer_color = NULL;
2544 m.pointer_color = varray_color4f;
2546 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2548 color[0] = bound(0, color2[0], 1);
2549 color[1] = bound(0, color2[1], 1);
2550 color[2] = bound(0, color2[2], 1);
2551 if (r_textureunits.integer >= 3)
2552 GL_Color(color[0], color[1], color[2], 1);
2553 else if (r_textureunits.integer >= 2)
2554 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2556 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2557 GL_LockArrays(firstvertex, numvertices);
2558 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2559 GL_LockArrays(0, 0);
2561 c_rt_lighttris += numtriangles;
2564 if (r_shadow_rtlight->diffusescale)
2566 GL_BlendFunc(GL_ONE, GL_ONE);
2567 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
2568 memset(&m, 0, sizeof(m));
2569 m.pointer_vertex = vertex3f;
2570 m.pointer_color = varray_color4f;
2571 m.tex[0] = R_GetTexture(basetexture);
2572 m.pointer_texcoord[0] = texcoord2f;
2573 if (r_textureunits.integer >= 2)
2576 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2578 m.pointer_texcoord3f[1] = vertex3f;
2579 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2581 m.pointer_texcoord[1] = varray_texcoord2f[1];
2582 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2584 if (r_textureunits.integer >= 3)
2586 // Geforce3/Radeon class but not using dot3
2587 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2589 m.pointer_texcoord3f[2] = vertex3f;
2590 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2592 m.pointer_texcoord[2] = varray_texcoord2f[2];
2593 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2598 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2600 color[0] = bound(0, color2[0], 1);
2601 color[1] = bound(0, color2[1], 1);
2602 color[2] = bound(0, color2[2], 1);
2603 if (r_textureunits.integer >= 3)
2604 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2605 else if (r_textureunits.integer >= 2)
2606 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2608 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2609 GL_LockArrays(firstvertex, numvertices);
2610 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2611 GL_LockArrays(0, 0);
2613 c_rt_lighttris += numtriangles;
2619 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2623 R_RTLight_Uncompile(rtlight);
2624 memset(rtlight, 0, sizeof(*rtlight));
2626 VectorCopy(light->origin, rtlight->shadoworigin);
2627 VectorCopy(light->color, rtlight->color);
2628 rtlight->radius = light->radius;
2629 //rtlight->cullradius = rtlight->radius;
2630 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2631 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2632 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2633 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2634 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2635 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2636 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2637 rtlight->cubemapname[0] = 0;
2638 if (light->cubemapname[0])
2639 strcpy(rtlight->cubemapname, light->cubemapname);
2640 else if (light->cubemapnum > 0)
2641 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2642 rtlight->shadow = light->shadow;
2643 rtlight->corona = light->corona;
2644 rtlight->style = light->style;
2645 rtlight->isstatic = isstatic;
2646 rtlight->coronasizescale = light->coronasizescale;
2647 rtlight->ambientscale = light->ambientscale;
2648 rtlight->diffusescale = light->diffusescale;
2649 rtlight->specularscale = light->specularscale;
2650 rtlight->flags = light->flags;
2651 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2652 // ConcatScale won't work here because this needs to scale rotate and
2653 // translate, not just rotate
2654 scale = 1.0f / rtlight->radius;
2655 for (k = 0;k < 3;k++)
2656 for (j = 0;j < 4;j++)
2657 rtlight->matrix_worldtolight.m[k][j] *= scale;
2659 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2660 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2661 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2662 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2665 // compiles rtlight geometry
2666 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2667 void R_RTLight_Compile(rtlight_t *rtlight)
2669 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2670 entity_render_t *ent = r_refdef.worldentity;
2671 model_t *model = r_refdef.worldmodel;
2674 // compile the light
2675 rtlight->compiled = true;
2676 rtlight->static_numleafs = 0;
2677 rtlight->static_numleafpvsbytes = 0;
2678 rtlight->static_leaflist = NULL;
2679 rtlight->static_leafpvs = NULL;
2680 rtlight->static_numsurfaces = 0;
2681 rtlight->static_surfacelist = NULL;
2682 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2683 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2684 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2685 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2686 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2687 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2689 if (model && model->GetLightInfo)
2691 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2692 r_shadow_compilingrtlight = rtlight;
2693 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->brush.num_surfaces);
2694 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2695 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2696 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2697 rtlight->static_numleafs = numleafs;
2698 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2699 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2700 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2701 rtlight->static_numsurfaces = numsurfaces;
2702 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2704 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2705 if (numleafpvsbytes)
2706 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2708 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2709 if (model->DrawShadowVolume && rtlight->shadow)
2711 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2712 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2713 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2715 if (model->DrawLight)
2717 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2718 model->DrawLight(ent, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
2719 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2721 // switch back to rendering when DrawShadowVolume or DrawLight is called
2722 r_shadow_compilingrtlight = NULL;
2726 // use smallest available cullradius - box radius or light radius
2727 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2728 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2732 if (rtlight->static_meshchain_shadow)
2735 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2738 shadowtris += mesh->numtriangles;
2744 if (rtlight->static_meshchain_light)
2747 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2750 lighttris += mesh->numtriangles;
2754 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);
2757 void R_RTLight_Uncompile(rtlight_t *rtlight)
2759 if (rtlight->compiled)
2761 if (rtlight->static_meshchain_shadow)
2762 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2763 rtlight->static_meshchain_shadow = NULL;
2764 if (rtlight->static_meshchain_light)
2765 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2766 rtlight->static_meshchain_light = NULL;
2767 // these allocations are grouped
2768 if (rtlight->static_leaflist)
2769 Mem_Free(rtlight->static_leaflist);
2770 rtlight->static_numleafs = 0;
2771 rtlight->static_numleafpvsbytes = 0;
2772 rtlight->static_leaflist = NULL;
2773 rtlight->static_leafpvs = NULL;
2774 rtlight->static_numsurfaces = 0;
2775 rtlight->static_surfacelist = NULL;
2776 rtlight->compiled = false;
2780 void R_Shadow_UncompileWorldLights(void)
2783 for (light = r_shadow_worldlightchain;light;light = light->next)
2784 R_RTLight_Uncompile(&light->rtlight);
2787 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2789 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2790 vec_t relativeshadowradius;
2791 if (ent == r_refdef.worldentity)
2793 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2796 R_Mesh_Matrix(&ent->matrix);
2797 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2799 R_Mesh_VertexPointer(mesh->vertex3f);
2800 GL_LockArrays(0, mesh->numverts);
2801 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2803 // increment stencil if backface is behind depthbuffer
2804 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2805 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2806 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2807 c_rtcached_shadowmeshes++;
2808 c_rtcached_shadowtris += mesh->numtriangles;
2809 // decrement stencil if frontface is behind depthbuffer
2810 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2811 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2813 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2814 c_rtcached_shadowmeshes++;
2815 c_rtcached_shadowtris += mesh->numtriangles;
2816 GL_LockArrays(0, 0);
2819 else if (numsurfaces)
2821 R_Mesh_Matrix(&ent->matrix);
2822 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2827 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2828 relativeshadowradius = rtlight->radius / ent->scale;
2829 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2830 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2831 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2832 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2833 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2834 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2835 R_Mesh_Matrix(&ent->matrix);
2836 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2840 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2843 // set up properties for rendering light onto this entity
2844 r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2845 r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2846 r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2847 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2848 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2849 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2850 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2851 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2852 R_Mesh_Matrix(&ent->matrix);
2853 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2855 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2856 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2857 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2858 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2860 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2863 if (ent == r_refdef.worldentity)
2865 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2867 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2868 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, r_shadow_entitylightcolor, vec3_origin, vec3_origin, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular);
2871 ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2874 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2877 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2882 int numleafs, numsurfaces;
2883 int *leaflist, *surfacelist;
2885 int numlightentities;
2886 int numshadowentities;
2887 entity_render_t *lightentities[MAX_EDICTS];
2888 entity_render_t *shadowentities[MAX_EDICTS];
2890 // skip lights that don't light (corona only lights)
2891 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2894 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2895 VectorScale(rtlight->color, f, lightcolor);
2896 if (VectorLength2(lightcolor) < 0.01)
2899 if (rtlight->selected)
2901 f = 2 + sin(realtime * M_PI * 4.0);
2902 VectorScale(lightcolor, f, lightcolor);
2906 // loading is done before visibility checks because loading should happen
2907 // all at once at the start of a level, not when it stalls gameplay.
2908 // (especially important to benchmarks)
2910 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2911 R_RTLight_Compile(rtlight);
2913 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2915 // if the light box is offscreen, skip it
2916 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2919 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2921 // compiled light, world available and can receive realtime lighting
2922 // retrieve leaf information
2923 numleafs = rtlight->static_numleafs;
2924 leaflist = rtlight->static_leaflist;
2925 leafpvs = rtlight->static_leafpvs;
2926 numsurfaces = rtlight->static_numsurfaces;
2927 surfacelist = rtlight->static_surfacelist;
2929 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2931 // dynamic light, world available and can receive realtime lighting
2932 // calculate lit surfaces and leafs
2933 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
2934 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2935 leaflist = r_shadow_buffer_leaflist;
2936 leafpvs = r_shadow_buffer_leafpvs;
2937 surfacelist = r_shadow_buffer_surfacelist;
2938 // if the reduced leaf bounds are offscreen, skip it
2939 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2951 // check if light is illuminating any visible leafs
2954 for (i = 0;i < numleafs;i++)
2955 if (r_worldleafvisible[leaflist[i]])
2960 // set up a scissor rectangle for this light
2961 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2964 numlightentities = 0;
2966 lightentities[numlightentities++] = r_refdef.worldentity;
2967 numshadowentities = 0;
2969 shadowentities[numshadowentities++] = r_refdef.worldentity;
2970 if (r_drawentities.integer)
2972 for (i = 0;i < r_refdef.numentities;i++)
2974 entity_render_t *ent = r_refdef.entities[i];
2975 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2977 && !(ent->flags & RENDER_TRANSPARENT)
2978 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2980 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2981 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2982 shadowentities[numshadowentities++] = ent;
2983 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2984 lightentities[numlightentities++] = ent;
2989 // return if there's nothing at all to light
2990 if (!numlightentities)
2993 R_Shadow_Stage_ActiveLight(rtlight);
2997 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
3000 R_Shadow_Stage_StencilShadowVolumes();
3001 for (i = 0;i < numshadowentities;i++)
3002 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
3005 if (numlightentities && !visible)
3007 R_Shadow_Stage_Lighting(usestencil);
3008 for (i = 0;i < numlightentities;i++)
3009 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
3012 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
3014 R_Shadow_Stage_VisibleShadowVolumes();
3015 for (i = 0;i < numshadowentities;i++)
3016 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
3019 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
3021 R_Shadow_Stage_VisibleLighting(usestencil);
3022 for (i = 0;i < numlightentities;i++)
3023 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
3027 void R_ShadowVolumeLighting(qboolean visible)
3032 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3033 R_Shadow_EditLights_Reload_f();
3035 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, visible);
3045 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3046 if (light->flags & flag)
3047 R_DrawRTLight(&light->rtlight, visible);
3049 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
3050 R_DrawRTLight(&light->rtlight, visible);
3052 R_Shadow_Stage_End();
3055 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3056 typedef struct suffixinfo_s
3059 qboolean flipx, flipy, flipdiagonal;
3062 static suffixinfo_t suffix[3][6] =
3065 {"px", false, false, false},
3066 {"nx", false, false, false},
3067 {"py", false, false, false},
3068 {"ny", false, false, false},
3069 {"pz", false, false, false},
3070 {"nz", false, false, false}
3073 {"posx", false, false, false},
3074 {"negx", false, false, false},
3075 {"posy", false, false, false},
3076 {"negy", false, false, false},
3077 {"posz", false, false, false},
3078 {"negz", false, false, false}
3081 {"rt", true, false, true},
3082 {"lf", false, true, true},
3083 {"ft", true, true, false},
3084 {"bk", false, false, false},
3085 {"up", true, false, true},
3086 {"dn", true, false, true}
3090 static int componentorder[4] = {0, 1, 2, 3};
3092 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3094 int i, j, cubemapsize;
3095 qbyte *cubemappixels, *image_rgba;
3096 rtexture_t *cubemaptexture;
3098 // must start 0 so the first loadimagepixels has no requested width/height
3100 cubemappixels = NULL;
3101 cubemaptexture = NULL;
3102 // keep trying different suffix groups (posx, px, rt) until one loads
3103 for (j = 0;j < 3 && !cubemappixels;j++)
3105 // load the 6 images in the suffix group
3106 for (i = 0;i < 6;i++)
3108 // generate an image name based on the base and and suffix
3109 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3111 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3113 // an image loaded, make sure width and height are equal
3114 if (image_width == image_height)
3116 // if this is the first image to load successfully, allocate the cubemap memory
3117 if (!cubemappixels && image_width >= 1)
3119 cubemapsize = image_width;
3120 // note this clears to black, so unavailable sides are black
3121 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3123 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3125 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);
3128 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3130 Mem_Free(image_rgba);
3134 // if a cubemap loaded, upload it
3137 if (!r_shadow_filters_texturepool)
3138 r_shadow_filters_texturepool = R_AllocTexturePool();
3139 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3140 Mem_Free(cubemappixels);
3144 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3145 for (j = 0;j < 3;j++)
3146 for (i = 0;i < 6;i++)
3147 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3148 Con_Print(" and was unable to find any of them.\n");
3150 return cubemaptexture;
3153 rtexture_t *R_Shadow_Cubemap(const char *basename)
3156 for (i = 0;i < numcubemaps;i++)
3157 if (!strcasecmp(cubemaps[i].basename, basename))
3158 return cubemaps[i].texture;
3159 if (i >= MAX_CUBEMAPS)
3160 return r_texture_whitecube;
3162 strcpy(cubemaps[i].basename, basename);
3163 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3164 return cubemaps[i].texture;
3167 void R_Shadow_FreeCubemaps(void)
3170 R_FreeTexturePool(&r_shadow_filters_texturepool);
3173 dlight_t *R_Shadow_NewWorldLight(void)
3176 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3177 light->next = r_shadow_worldlightchain;
3178 r_shadow_worldlightchain = light;
3182 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)
3184 VectorCopy(origin, light->origin);
3185 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3186 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3187 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3188 light->color[0] = max(color[0], 0);
3189 light->color[1] = max(color[1], 0);
3190 light->color[2] = max(color[2], 0);
3191 light->radius = max(radius, 0);
3192 light->style = style;
3193 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3195 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3198 light->shadow = shadowenable;
3199 light->corona = corona;
3202 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3203 light->coronasizescale = coronasizescale;
3204 light->ambientscale = ambientscale;
3205 light->diffusescale = diffusescale;
3206 light->specularscale = specularscale;
3207 light->flags = flags;
3208 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3210 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3213 void R_Shadow_FreeWorldLight(dlight_t *light)
3215 dlight_t **lightpointer;
3216 R_RTLight_Uncompile(&light->rtlight);
3217 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3218 if (*lightpointer != light)
3219 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3220 *lightpointer = light->next;
3224 void R_Shadow_ClearWorldLights(void)
3226 while (r_shadow_worldlightchain)
3227 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3228 r_shadow_selectedlight = NULL;
3229 R_Shadow_FreeCubemaps();
3232 void R_Shadow_SelectLight(dlight_t *light)
3234 if (r_shadow_selectedlight)
3235 r_shadow_selectedlight->selected = false;
3236 r_shadow_selectedlight = light;
3237 if (r_shadow_selectedlight)
3238 r_shadow_selectedlight->selected = true;
3241 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3243 float scale = r_editlights_cursorgrid.value * 0.5f;
3244 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);
3247 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3250 const dlight_t *light;
3253 if (light->selected)
3254 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3257 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);
3260 void R_Shadow_DrawLightSprites(void)
3266 for (i = 0;i < 5;i++)
3268 lighttextures[i] = NULL;
3269 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3270 lighttextures[i] = pic->tex;
3273 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3274 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3275 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3278 void R_Shadow_SelectLightInView(void)
3280 float bestrating, rating, temp[3];
3281 dlight_t *best, *light;
3284 for (light = r_shadow_worldlightchain;light;light = light->next)
3286 VectorSubtract(light->origin, r_vieworigin, temp);
3287 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3290 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3291 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3293 bestrating = rating;
3298 R_Shadow_SelectLight(best);
3301 void R_Shadow_LoadWorldLights(void)
3303 int n, a, style, shadow, flags;
3304 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3305 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3306 if (r_refdef.worldmodel == NULL)
3308 Con_Print("No map loaded.\n");
3311 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3312 strlcat (name, ".rtlights", sizeof (name));
3313 lightsstring = FS_LoadFile(name, tempmempool, false);
3323 for (;COM_Parse(t, true) && strcmp(
3324 if (COM_Parse(t, true))
3326 if (com_token[0] == '!')
3329 origin[0] = atof(com_token+1);
3332 origin[0] = atof(com_token);
3337 while (*s && *s != '\n' && *s != '\r')
3343 // check for modifier flags
3350 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);
3353 flags = LIGHTFLAG_REALTIMEMODE;
3361 coronasizescale = 0.25f;
3363 VectorClear(angles);
3366 if (a < 9 || !strcmp(cubemapname, "\"\""))
3368 // remove quotes on cubemapname
3369 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3371 cubemapname[strlen(cubemapname)-1] = 0;
3372 strcpy(cubemapname, cubemapname + 1);
3376 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);
3379 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3380 radius *= r_editlights_rtlightssizescale.value;
3381 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3389 Con_Printf("invalid rtlights file \"%s\"\n", name);
3390 Mem_Free(lightsstring);
3394 void R_Shadow_SaveWorldLights(void)
3397 int bufchars, bufmaxchars;
3399 char name[MAX_QPATH];
3401 if (!r_shadow_worldlightchain)
3403 if (r_refdef.worldmodel == NULL)
3405 Con_Print("No map loaded.\n");
3408 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3409 strlcat (name, ".rtlights", sizeof (name));
3410 bufchars = bufmaxchars = 0;
3412 for (light = r_shadow_worldlightchain;light;light = light->next)
3414 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3415 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);
3416 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3417 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]);
3419 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);
3420 if (bufchars + (int) strlen(line) > bufmaxchars)
3422 bufmaxchars = bufchars + strlen(line) + 2048;
3424 buf = Mem_Alloc(tempmempool, bufmaxchars);
3428 memcpy(buf, oldbuf, bufchars);
3434 memcpy(buf + bufchars, line, strlen(line));
3435 bufchars += strlen(line);
3439 FS_WriteFile(name, buf, bufchars);
3444 void R_Shadow_LoadLightsFile(void)
3447 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3448 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3449 if (r_refdef.worldmodel == NULL)
3451 Con_Print("No map loaded.\n");
3454 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3455 strlcat (name, ".lights", sizeof (name));
3456 lightsstring = FS_LoadFile(name, tempmempool, false);
3464 while (*s && *s != '\n' && *s != '\r')
3470 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);
3474 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);
3477 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3478 radius = bound(15, radius, 4096);
3479 VectorScale(color, (2.0f / (8388608.0f)), color);
3480 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3488 Con_Printf("invalid lights file \"%s\"\n", name);
3489 Mem_Free(lightsstring);
3493 // tyrlite/hmap2 light types in the delay field
3494 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3496 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3498 int entnum, style, islight, skin, pflags, effects, type, n;
3501 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3502 char key[256], value[1024];
3504 if (r_refdef.worldmodel == NULL)
3506 Con_Print("No map loaded.\n");
3509 // try to load a .ent file first
3510 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3511 strlcat (key, ".ent", sizeof (key));
3512 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3513 // and if that is not found, fall back to the bsp file entity string
3515 data = r_refdef.worldmodel->brush.entities;
3518 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3520 type = LIGHTTYPE_MINUSX;
3521 origin[0] = origin[1] = origin[2] = 0;
3522 originhack[0] = originhack[1] = originhack[2] = 0;
3523 angles[0] = angles[1] = angles[2] = 0;
3524 color[0] = color[1] = color[2] = 1;
3525 light[0] = light[1] = light[2] = 1;light[3] = 300;
3526 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3536 if (!COM_ParseToken(&data, false))
3538 if (com_token[0] == '}')
3539 break; // end of entity
3540 if (com_token[0] == '_')
3541 strcpy(key, com_token + 1);
3543 strcpy(key, com_token);
3544 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3545 key[strlen(key)-1] = 0;
3546 if (!COM_ParseToken(&data, false))
3548 strcpy(value, com_token);
3550 // now that we have the key pair worked out...
3551 if (!strcmp("light", key))
3553 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3557 light[0] = vec[0] * (1.0f / 256.0f);
3558 light[1] = vec[0] * (1.0f / 256.0f);
3559 light[2] = vec[0] * (1.0f / 256.0f);
3565 light[0] = vec[0] * (1.0f / 255.0f);
3566 light[1] = vec[1] * (1.0f / 255.0f);
3567 light[2] = vec[2] * (1.0f / 255.0f);
3571 else if (!strcmp("delay", key))
3573 else if (!strcmp("origin", key))
3574 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3575 else if (!strcmp("angle", key))
3576 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3577 else if (!strcmp("angles", key))
3578 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3579 else if (!strcmp("color", key))
3580 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3581 else if (!strcmp("wait", key))
3582 fadescale = atof(value);
3583 else if (!strcmp("classname", key))
3585 if (!strncmp(value, "light", 5))
3588 if (!strcmp(value, "light_fluoro"))
3593 overridecolor[0] = 1;
3594 overridecolor[1] = 1;
3595 overridecolor[2] = 1;
3597 if (!strcmp(value, "light_fluorospark"))
3602 overridecolor[0] = 1;
3603 overridecolor[1] = 1;
3604 overridecolor[2] = 1;
3606 if (!strcmp(value, "light_globe"))
3611 overridecolor[0] = 1;
3612 overridecolor[1] = 0.8;
3613 overridecolor[2] = 0.4;
3615 if (!strcmp(value, "light_flame_large_yellow"))
3620 overridecolor[0] = 1;
3621 overridecolor[1] = 0.5;
3622 overridecolor[2] = 0.1;
3624 if (!strcmp(value, "light_flame_small_yellow"))
3629 overridecolor[0] = 1;
3630 overridecolor[1] = 0.5;
3631 overridecolor[2] = 0.1;
3633 if (!strcmp(value, "light_torch_small_white"))
3638 overridecolor[0] = 1;
3639 overridecolor[1] = 0.5;
3640 overridecolor[2] = 0.1;
3642 if (!strcmp(value, "light_torch_small_walltorch"))
3647 overridecolor[0] = 1;
3648 overridecolor[1] = 0.5;
3649 overridecolor[2] = 0.1;
3653 else if (!strcmp("style", key))
3654 style = atoi(value);
3655 else if (r_refdef.worldmodel->type == mod_brushq3)
3657 if (!strcmp("scale", key))
3658 lightscale = atof(value);
3659 if (!strcmp("fade", key))
3660 fadescale = atof(value);
3662 else if (!strcmp("skin", key))
3663 skin = (int)atof(value);
3664 else if (!strcmp("pflags", key))
3665 pflags = (int)atof(value);
3666 else if (!strcmp("effects", key))
3667 effects = (int)atof(value);
3671 if (lightscale <= 0)
3675 if (color[0] == color[1] && color[0] == color[2])
3677 color[0] *= overridecolor[0];
3678 color[1] *= overridecolor[1];
3679 color[2] *= overridecolor[2];
3681 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3682 color[0] = color[0] * light[0];
3683 color[1] = color[1] * light[1];
3684 color[2] = color[2] * light[2];
3687 case LIGHTTYPE_MINUSX:
3689 case LIGHTTYPE_RECIPX:
3691 VectorScale(color, (1.0f / 16.0f), color);
3693 case LIGHTTYPE_RECIPXX:
3695 VectorScale(color, (1.0f / 16.0f), color);
3698 case LIGHTTYPE_NONE:
3702 case LIGHTTYPE_MINUSXX:
3705 VectorAdd(origin, originhack, origin);
3707 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);
3710 Mem_Free(entfiledata);
3714 void R_Shadow_SetCursorLocationForView(void)
3717 vec3_t dest, endpos;
3719 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3720 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3721 if (trace.fraction < 1)
3723 dist = trace.fraction * r_editlights_cursordistance.value;
3724 push = r_editlights_cursorpushback.value;
3728 VectorMA(trace.endpos, push, r_viewforward, endpos);
3729 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3731 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3732 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3733 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3736 void R_Shadow_UpdateWorldLightSelection(void)
3738 if (r_editlights.integer)
3740 R_Shadow_SetCursorLocationForView();
3741 R_Shadow_SelectLightInView();
3742 R_Shadow_DrawLightSprites();
3745 R_Shadow_SelectLight(NULL);
3748 void R_Shadow_EditLights_Clear_f(void)
3750 R_Shadow_ClearWorldLights();
3753 void R_Shadow_EditLights_Reload_f(void)
3755 if (!r_refdef.worldmodel)
3757 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3758 R_Shadow_ClearWorldLights();
3759 R_Shadow_LoadWorldLights();
3760 if (r_shadow_worldlightchain == NULL)
3762 R_Shadow_LoadLightsFile();
3763 if (r_shadow_worldlightchain == NULL)
3764 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3768 void R_Shadow_EditLights_Save_f(void)
3770 if (!r_refdef.worldmodel)
3772 R_Shadow_SaveWorldLights();
3775 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3777 R_Shadow_ClearWorldLights();
3778 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3781 void R_Shadow_EditLights_ImportLightsFile_f(void)
3783 R_Shadow_ClearWorldLights();
3784 R_Shadow_LoadLightsFile();
3787 void R_Shadow_EditLights_Spawn_f(void)
3790 if (!r_editlights.integer)
3792 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3795 if (Cmd_Argc() != 1)
3797 Con_Print("r_editlights_spawn does not take parameters\n");
3800 color[0] = color[1] = color[2] = 1;
3801 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3804 void R_Shadow_EditLights_Edit_f(void)
3806 vec3_t origin, angles, color;
3807 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3808 int style, shadows, flags, normalmode, realtimemode;
3809 char cubemapname[1024];
3810 if (!r_editlights.integer)
3812 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3815 if (!r_shadow_selectedlight)
3817 Con_Print("No selected light.\n");
3820 VectorCopy(r_shadow_selectedlight->origin, origin);
3821 VectorCopy(r_shadow_selectedlight->angles, angles);
3822 VectorCopy(r_shadow_selectedlight->color, color);
3823 radius = r_shadow_selectedlight->radius;
3824 style = r_shadow_selectedlight->style;
3825 if (r_shadow_selectedlight->cubemapname)
3826 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3829 shadows = r_shadow_selectedlight->shadow;
3830 corona = r_shadow_selectedlight->corona;
3831 coronasizescale = r_shadow_selectedlight->coronasizescale;
3832 ambientscale = r_shadow_selectedlight->ambientscale;
3833 diffusescale = r_shadow_selectedlight->diffusescale;
3834 specularscale = r_shadow_selectedlight->specularscale;
3835 flags = r_shadow_selectedlight->flags;
3836 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3837 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3838 if (!strcmp(Cmd_Argv(1), "origin"))
3840 if (Cmd_Argc() != 5)
3842 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3845 origin[0] = atof(Cmd_Argv(2));
3846 origin[1] = atof(Cmd_Argv(3));
3847 origin[2] = atof(Cmd_Argv(4));
3849 else if (!strcmp(Cmd_Argv(1), "originx"))
3851 if (Cmd_Argc() != 3)
3853 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3856 origin[0] = atof(Cmd_Argv(2));
3858 else if (!strcmp(Cmd_Argv(1), "originy"))
3860 if (Cmd_Argc() != 3)
3862 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3865 origin[1] = atof(Cmd_Argv(2));
3867 else if (!strcmp(Cmd_Argv(1), "originz"))
3869 if (Cmd_Argc() != 3)
3871 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3874 origin[2] = atof(Cmd_Argv(2));
3876 else if (!strcmp(Cmd_Argv(1), "move"))
3878 if (Cmd_Argc() != 5)
3880 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3883 origin[0] += atof(Cmd_Argv(2));
3884 origin[1] += atof(Cmd_Argv(3));
3885 origin[2] += atof(Cmd_Argv(4));
3887 else if (!strcmp(Cmd_Argv(1), "movex"))
3889 if (Cmd_Argc() != 3)
3891 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3894 origin[0] += atof(Cmd_Argv(2));
3896 else if (!strcmp(Cmd_Argv(1), "movey"))
3898 if (Cmd_Argc() != 3)
3900 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3903 origin[1] += atof(Cmd_Argv(2));
3905 else if (!strcmp(Cmd_Argv(1), "movez"))
3907 if (Cmd_Argc() != 3)
3909 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3912 origin[2] += atof(Cmd_Argv(2));
3914 else if (!strcmp(Cmd_Argv(1), "angles"))
3916 if (Cmd_Argc() != 5)
3918 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3921 angles[0] = atof(Cmd_Argv(2));
3922 angles[1] = atof(Cmd_Argv(3));
3923 angles[2] = atof(Cmd_Argv(4));
3925 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3927 if (Cmd_Argc() != 3)
3929 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3932 angles[0] = atof(Cmd_Argv(2));
3934 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3936 if (Cmd_Argc() != 3)
3938 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3941 angles[1] = atof(Cmd_Argv(2));
3943 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3945 if (Cmd_Argc() != 3)
3947 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3950 angles[2] = atof(Cmd_Argv(2));
3952 else if (!strcmp(Cmd_Argv(1), "color"))
3954 if (Cmd_Argc() != 5)
3956 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3959 color[0] = atof(Cmd_Argv(2));
3960 color[1] = atof(Cmd_Argv(3));
3961 color[2] = atof(Cmd_Argv(4));
3963 else if (!strcmp(Cmd_Argv(1), "radius"))
3965 if (Cmd_Argc() != 3)
3967 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3970 radius = atof(Cmd_Argv(2));
3972 else if (!strcmp(Cmd_Argv(1), "style"))
3974 if (Cmd_Argc() != 3)
3976 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3979 style = atoi(Cmd_Argv(2));
3981 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3985 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3988 if (Cmd_Argc() == 3)
3989 strcpy(cubemapname, Cmd_Argv(2));
3993 else if (!strcmp(Cmd_Argv(1), "shadows"))
3995 if (Cmd_Argc() != 3)
3997 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4000 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4002 else if (!strcmp(Cmd_Argv(1), "corona"))
4004 if (Cmd_Argc() != 3)
4006 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4009 corona = atof(Cmd_Argv(2));
4011 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4013 if (Cmd_Argc() != 3)
4015 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4018 coronasizescale = atof(Cmd_Argv(2));
4020 else if (!strcmp(Cmd_Argv(1), "ambient"))
4022 if (Cmd_Argc() != 3)
4024 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4027 ambientscale = atof(Cmd_Argv(2));
4029 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4031 if (Cmd_Argc() != 3)
4033 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4036 diffusescale = atof(Cmd_Argv(2));
4038 else if (!strcmp(Cmd_Argv(1), "specular"))
4040 if (Cmd_Argc() != 3)
4042 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4045 specularscale = atof(Cmd_Argv(2));
4047 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4049 if (Cmd_Argc() != 3)
4051 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4054 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4056 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4058 if (Cmd_Argc() != 3)
4060 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4063 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4067 Con_Print("usage: r_editlights_edit [property] [value]\n");
4068 Con_Print("Selected light's properties:\n");
4069 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4070 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4071 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4072 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4073 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4074 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4075 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4076 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4077 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4078 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4079 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4080 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4081 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4082 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4085 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4086 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4089 void R_Shadow_EditLights_EditAll_f(void)
4093 if (!r_editlights.integer)
4095 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4099 for (light = r_shadow_worldlightchain;light;light = light->next)
4101 R_Shadow_SelectLight(light);
4102 R_Shadow_EditLights_Edit_f();
4106 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4108 int lightnumber, lightcount;
4112 if (!r_editlights.integer)
4118 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4119 if (light == r_shadow_selectedlight)
4120 lightnumber = lightcount;
4121 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;
4122 if (r_shadow_selectedlight == NULL)
4124 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4125 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;
4126 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;
4127 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;
4128 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4129 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4130 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4131 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;
4132 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4133 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4134 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4135 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4136 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4137 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;
4138 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;
4141 void R_Shadow_EditLights_ToggleShadow_f(void)
4143 if (!r_editlights.integer)
4145 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4148 if (!r_shadow_selectedlight)
4150 Con_Print("No selected light.\n");
4153 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);
4156 void R_Shadow_EditLights_ToggleCorona_f(void)
4158 if (!r_editlights.integer)
4160 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4163 if (!r_shadow_selectedlight)
4165 Con_Print("No selected light.\n");
4168 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);
4171 void R_Shadow_EditLights_Remove_f(void)
4173 if (!r_editlights.integer)
4175 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4178 if (!r_shadow_selectedlight)
4180 Con_Print("No selected light.\n");
4183 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4184 r_shadow_selectedlight = NULL;
4187 void R_Shadow_EditLights_Help_f(void)
4190 "Documentation on r_editlights system:\n"
4192 "r_editlights : enable/disable editing mode\n"
4193 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4194 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4195 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4196 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4197 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4198 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4199 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4201 "r_editlights_help : this help\n"
4202 "r_editlights_clear : remove all lights\n"
4203 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4204 "r_editlights_save : save to .rtlights file\n"
4205 "r_editlights_spawn : create a light with default settings\n"
4206 "r_editlights_edit command : edit selected light - more documentation below\n"
4207 "r_editlights_remove : remove selected light\n"
4208 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4209 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4210 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4212 "origin x y z : set light location\n"
4213 "originx x: set x component of light location\n"
4214 "originy y: set y component of light location\n"
4215 "originz z: set z component of light location\n"
4216 "move x y z : adjust light location\n"
4217 "movex x: adjust x component of light location\n"
4218 "movey y: adjust y component of light location\n"
4219 "movez z: adjust z component of light location\n"
4220 "angles x y z : set light angles\n"
4221 "anglesx x: set x component of light angles\n"
4222 "anglesy y: set y component of light angles\n"
4223 "anglesz z: set z component of light angles\n"
4224 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4225 "radius radius : set radius (size) of light\n"
4226 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4227 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4228 "shadows 1/0 : turn on/off shadows\n"
4229 "corona n : set corona intensity\n"
4230 "coronasize n : set corona size (0-1)\n"
4231 "ambient n : set ambient intensity (0-1)\n"
4232 "diffuse n : set diffuse intensity (0-1)\n"
4233 "specular n : set specular intensity (0-1)\n"
4234 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4235 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4236 "<nothing> : print light properties to console\n"
4240 void R_Shadow_EditLights_CopyInfo_f(void)
4242 if (!r_editlights.integer)
4244 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4247 if (!r_shadow_selectedlight)
4249 Con_Print("No selected light.\n");
4252 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4253 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4254 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4255 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4256 if (r_shadow_selectedlight->cubemapname)
4257 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4259 r_shadow_bufferlight.cubemapname[0] = 0;
4260 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4261 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4262 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4263 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4264 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4265 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4266 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4269 void R_Shadow_EditLights_PasteInfo_f(void)
4271 if (!r_editlights.integer)
4273 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4276 if (!r_shadow_selectedlight)
4278 Con_Print("No selected light.\n");
4281 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);
4284 void R_Shadow_EditLights_Init(void)
4286 Cvar_RegisterVariable(&r_editlights);
4287 Cvar_RegisterVariable(&r_editlights_cursordistance);
4288 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4289 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4290 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4291 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4292 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4293 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4294 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4295 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4296 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4297 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4298 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4299 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4300 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4301 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4302 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4303 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4304 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4305 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4306 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4307 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);