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 normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadowstage_e
148 R_SHADOWSTAGE_STENCIL,
149 R_SHADOWSTAGE_STENCILTWOSIDE,
150 R_SHADOWSTAGE_LIGHT_VERTEX,
151 R_SHADOWSTAGE_LIGHT_DOT3,
152 R_SHADOWSTAGE_LIGHT_GLSL,
153 R_SHADOWSTAGE_VISIBLEVOLUMES,
154 R_SHADOWSTAGE_VISIBLELIGHTING,
158 r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
160 mempool_t *r_shadow_mempool;
162 int maxshadowelements;
176 int r_shadow_buffer_numleafpvsbytes;
177 qbyte *r_shadow_buffer_leafpvs;
178 int *r_shadow_buffer_leaflist;
180 int r_shadow_buffer_numsurfacepvsbytes;
181 qbyte *r_shadow_buffer_surfacepvs;
182 int *r_shadow_buffer_surfacelist;
184 rtexturepool_t *r_shadow_texturepool;
185 rtexture_t *r_shadow_attenuation2dtexture;
186 rtexture_t *r_shadow_attenuation3dtexture;
188 // lights are reloaded when this changes
189 char r_shadow_mapname[MAX_QPATH];
191 // used only for light filters (cubemaps)
192 rtexturepool_t *r_shadow_filters_texturepool;
194 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
195 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
196 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
197 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
198 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
199 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
200 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
201 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
202 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
203 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
204 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
205 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
206 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
207 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
208 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
209 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
210 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
211 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
212 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
213 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
214 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
215 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
216 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
217 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
218 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
219 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
220 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
221 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
222 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
223 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "0"};
224 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
225 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
226 cvar_t r_shadow_glsl_geforcefxlowquality = {0, "r_shadow_glsl_geforcefxlowquality", "1"};
227 cvar_t r_shadow_glsl_surfacenormalize = {0, "r_shadow_glsl_surfacenormalize", "1"};
228 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
229 cvar_t r_editlights = {0, "r_editlights", "0"};
230 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
231 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
232 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
233 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
234 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
236 float r_shadow_attenpower, r_shadow_attenscale;
238 rtlight_t *r_shadow_compilingrtlight;
239 dlight_t *r_shadow_worldlightchain;
240 dlight_t *r_shadow_selectedlight;
241 dlight_t r_shadow_bufferlight;
242 vec3_t r_editlights_cursorlocation;
244 rtexture_t *lighttextures[5];
246 extern int con_vislines;
248 typedef struct cubemapinfo_s
255 #define MAX_CUBEMAPS 256
256 static int numcubemaps;
257 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
259 #define SHADERPERMUTATION_SPECULAR (1<<0)
260 #define SHADERPERMUTATION_FOG (1<<1)
261 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
262 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
263 #define SHADERPERMUTATION_SURFACENORMALIZE (1<<4)
264 #define SHADERPERMUTATION_GEFORCEFX (1<<5)
265 #define SHADERPERMUTATION_COUNT (1<<6)
267 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
269 void R_Shadow_UncompileWorldLights(void);
270 void R_Shadow_ClearWorldLights(void);
271 void R_Shadow_SaveWorldLights(void);
272 void R_Shadow_LoadWorldLights(void);
273 void R_Shadow_LoadLightsFile(void);
274 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
275 void R_Shadow_EditLights_Reload_f(void);
276 void R_Shadow_ValidateCvars(void);
277 static void R_Shadow_MakeTextures(void);
278 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
280 const char *builtinshader_light_vert =
281 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
282 "// written by Forest 'LordHavoc' Hale\n"
284 "uniform vec3 LightPosition;\n"
286 "varying vec2 TexCoord;\n"
287 "varying vec3 CubeVector;\n"
288 "varying vec3 LightVector;\n"
290 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
291 "uniform vec3 EyePosition;\n"
292 "varying vec3 EyeVector;\n"
295 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
299 " // copy the surface texcoord\n"
300 " TexCoord = gl_MultiTexCoord0.st;\n"
302 " // transform vertex position into light attenuation/cubemap space\n"
303 " // (-1 to +1 across the light box)\n"
304 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
306 " // transform unnormalized light direction into tangent space\n"
307 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
308 " // normalize it per pixel)\n"
309 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
310 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
311 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
312 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
314 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
315 " // transform unnormalized eye direction into tangent space\n"
316 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
317 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
318 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
319 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
322 " // transform vertex to camera space, using ftransform to match non-VS\n"
324 " gl_Position = ftransform();\n"
328 const char *builtinshader_light_frag =
329 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
330 "// written by Forest 'LordHavoc' Hale\n"
332 "// use half floats on GEFORCEFX for math performance, otherwise don't\n"
333 "#ifndef GEFORCEFX\n"
334 "#define half float\n"
335 "#define hvec2 vec2\n"
336 "#define hvec3 vec3\n"
337 "#define hvec4 vec4\n"
340 "uniform hvec3 LightColor;\n"
341 "#ifdef USEOFFSETMAPPING\n"
342 "uniform half OffsetMapping_Scale;\n"
343 "uniform half OffsetMapping_Bias;\n"
345 "#ifdef USESPECULAR\n"
346 "uniform half SpecularPower;\n"
349 "uniform half FogRangeRecip;\n"
351 "uniform half AmbientScale;\n"
352 "uniform half DiffuseScale;\n"
353 "#ifdef USESPECULAR\n"
354 "uniform half SpecularScale;\n"
357 "uniform sampler2D Texture_Normal;\n"
358 "uniform sampler2D Texture_Color;\n"
359 "#ifdef USESPECULAR\n"
360 "uniform sampler2D Texture_Gloss;\n"
362 "#ifdef USECUBEFILTER\n"
363 "uniform samplerCube Texture_Cube;\n"
366 "uniform sampler2D Texture_FogMask;\n"
369 "varying vec2 TexCoord;\n"
370 "varying vec3 CubeVector;\n"
371 "varying vec3 LightVector;\n"
372 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
373 "varying vec3 EyeVector;\n"
380 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
381 " // center and sharp falloff at the edge, this is about the most efficient\n"
382 " // we can get away with as far as providing illumination.\n"
384 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
385 " // provide significant illumination, large = slow = pain.\n"
386 " half colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
390 " colorscale *= texture2D(Texture_FogMask, hvec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
393 "#ifdef USEOFFSETMAPPING\n"
394 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
395 " hvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
396 " hvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
397 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
398 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
399 "#define TexCoord TexCoordOffset\n"
402 " // get the surface normal\n"
403 "#ifdef SURFACENORMALIZE\n"
404 " hvec3 surfacenormal = normalize(hvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
406 " hvec3 surfacenormal = -1.0 + 2.0 * hvec3(texture2D(Texture_Normal, TexCoord));\n"
409 " // calculate shading\n"
410 " hvec3 diffusenormal = hvec3(normalize(LightVector));\n"
411 " hvec3 color = hvec3(texture2D(Texture_Color, TexCoord)) * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
412 "#ifdef USESPECULAR\n"
413 " hvec3 specularnormal = hvec3(normalize(diffusenormal + hvec3(normalize(EyeVector))));\n"
414 " color += hvec3(texture2D(Texture_Gloss, TexCoord)) * (SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower));\n"
417 "#ifdef USECUBEFILTER\n"
418 " // apply light cubemap filter\n"
419 " color *= hvec3(textureCube(Texture_Cube, CubeVector));\n"
422 " // calculate fragment color (apply light color and attenuation/fog scaling)\n"
423 " gl_FragColor = hvec4(color * LightColor * colorscale, 1);\n"
427 void r_shadow_start(void)
430 // if not a GeForce FX, turn off the lowquality cvar
431 if (strncmp(gl_renderer, "GeForce FX ", strlen("GeForce FX ")))
432 Cvar_SetValue("r_shadow_glsl_geforcefxlowquality", 0);
433 // allocate vertex processing arrays
435 r_shadow_attenuation2dtexture = NULL;
436 r_shadow_attenuation3dtexture = NULL;
437 r_shadow_texturepool = NULL;
438 r_shadow_filters_texturepool = NULL;
439 R_Shadow_ValidateCvars();
440 R_Shadow_MakeTextures();
441 maxshadowelements = 0;
442 shadowelements = NULL;
450 shadowmarklist = NULL;
452 r_shadow_buffer_numleafpvsbytes = 0;
453 r_shadow_buffer_leafpvs = NULL;
454 r_shadow_buffer_leaflist = NULL;
455 r_shadow_buffer_numsurfacepvsbytes = 0;
456 r_shadow_buffer_surfacepvs = NULL;
457 r_shadow_buffer_surfacelist = NULL;
458 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
459 r_shadow_program_light[i] = 0;
460 if (gl_support_fragment_shader)
462 char *vertstring, *fragstring;
463 int vertstrings_count;
464 int fragstrings_count;
465 const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
466 const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
467 vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false);
468 fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false);
469 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
471 vertstrings_count = 0;
472 fragstrings_count = 0;
473 if (i & SHADERPERMUTATION_SPECULAR)
475 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
476 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
478 if (i & SHADERPERMUTATION_FOG)
480 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
481 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
483 if (i & SHADERPERMUTATION_CUBEFILTER)
485 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
486 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
488 if (i & SHADERPERMUTATION_OFFSETMAPPING)
490 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
491 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
493 if (i & SHADERPERMUTATION_SURFACENORMALIZE)
495 vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
496 fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
498 if (i & SHADERPERMUTATION_GEFORCEFX)
500 vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
501 fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
503 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
504 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
505 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
506 if (!r_shadow_program_light[i])
508 Con_Printf("permutation %s %s %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" : "", i & 16 ? "surfacenormalize" : "", i & 32 ? "geforcefx" : "", "glsl/light");
511 qglUseProgramObjectARB(r_shadow_program_light[i]);
512 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
513 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
514 if (i & SHADERPERMUTATION_SPECULAR)
516 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
518 if (i & SHADERPERMUTATION_CUBEFILTER)
520 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
522 if (i & SHADERPERMUTATION_FOG)
524 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
527 qglUseProgramObjectARB(0);
529 Mem_Free(fragstring);
531 Mem_Free(vertstring);
535 void r_shadow_shutdown(void)
538 R_Shadow_UncompileWorldLights();
539 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
541 if (r_shadow_program_light[i])
543 GL_Backend_FreeProgram(r_shadow_program_light[i]);
544 r_shadow_program_light[i] = 0;
548 r_shadow_attenuation2dtexture = NULL;
549 r_shadow_attenuation3dtexture = NULL;
550 R_FreeTexturePool(&r_shadow_texturepool);
551 R_FreeTexturePool(&r_shadow_filters_texturepool);
552 maxshadowelements = 0;
554 Mem_Free(shadowelements);
555 shadowelements = NULL;
558 Mem_Free(vertexupdate);
561 Mem_Free(vertexremap);
567 Mem_Free(shadowmark);
570 Mem_Free(shadowmarklist);
571 shadowmarklist = NULL;
573 r_shadow_buffer_numleafpvsbytes = 0;
574 if (r_shadow_buffer_leafpvs)
575 Mem_Free(r_shadow_buffer_leafpvs);
576 r_shadow_buffer_leafpvs = NULL;
577 if (r_shadow_buffer_leaflist)
578 Mem_Free(r_shadow_buffer_leaflist);
579 r_shadow_buffer_leaflist = NULL;
580 r_shadow_buffer_numsurfacepvsbytes = 0;
581 if (r_shadow_buffer_surfacepvs)
582 Mem_Free(r_shadow_buffer_surfacepvs);
583 r_shadow_buffer_surfacepvs = NULL;
584 if (r_shadow_buffer_surfacelist)
585 Mem_Free(r_shadow_buffer_surfacelist);
586 r_shadow_buffer_surfacelist = NULL;
589 void r_shadow_newmap(void)
593 void R_Shadow_Help_f(void)
596 "Documentation on r_shadow system:\n"
598 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
599 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
600 "r_shadow_debuglight : render only this light number (-1 = all)\n"
601 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
602 "r_shadow_gloss2intensity : brightness of forced gloss\n"
603 "r_shadow_glossintensity : brightness of textured gloss\n"
604 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
605 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
606 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
607 "r_shadow_portallight : use portal visibility for static light precomputation\n"
608 "r_shadow_projectdistance : shadow volume projection distance\n"
609 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
610 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
611 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
612 "r_shadow_realtime_world : use high quality world lighting mode\n"
613 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
614 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
615 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
616 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
617 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
618 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
619 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
620 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
621 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
622 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
623 "r_shadow_glsl_geforcefxlowquality : use lower quality lighting\n"
624 "r_shadow_glsl_surfacenormalize : makes bumpmapping slightly higher quality\n"
625 "r_shadow_scissor : use scissor optimization\n"
626 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
627 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
628 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
629 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
630 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
631 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
633 "r_shadow_help : this help\n"
637 void R_Shadow_Init(void)
639 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
640 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
641 Cvar_RegisterVariable(&r_shadow_debuglight);
642 Cvar_RegisterVariable(&r_shadow_gloss);
643 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
644 Cvar_RegisterVariable(&r_shadow_glossintensity);
645 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
646 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
647 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
648 Cvar_RegisterVariable(&r_shadow_portallight);
649 Cvar_RegisterVariable(&r_shadow_projectdistance);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
651 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
652 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
653 Cvar_RegisterVariable(&r_shadow_realtime_world);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
660 Cvar_RegisterVariable(&r_shadow_scissor);
661 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
662 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
663 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
664 Cvar_RegisterVariable(&r_shadow_texture3d);
665 Cvar_RegisterVariable(&r_shadow_visiblelighting);
666 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
667 Cvar_RegisterVariable(&r_shadow_glsl);
668 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
669 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
670 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
671 Cvar_RegisterVariable(&r_shadow_glsl_geforcefxlowquality);
672 Cvar_RegisterVariable(&r_shadow_glsl_surfacenormalize);
673 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
674 if (gamemode == GAME_TENEBRAE)
676 Cvar_SetValue("r_shadow_gloss", 2);
677 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
679 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
680 R_Shadow_EditLights_Init();
681 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
682 r_shadow_worldlightchain = NULL;
683 maxshadowelements = 0;
684 shadowelements = NULL;
692 shadowmarklist = NULL;
694 r_shadow_buffer_numleafpvsbytes = 0;
695 r_shadow_buffer_leafpvs = NULL;
696 r_shadow_buffer_leaflist = NULL;
697 r_shadow_buffer_numsurfacepvsbytes = 0;
698 r_shadow_buffer_surfacepvs = NULL;
699 r_shadow_buffer_surfacelist = NULL;
700 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
703 matrix4x4_t matrix_attenuationxyz =
706 {0.5, 0.0, 0.0, 0.5},
707 {0.0, 0.5, 0.0, 0.5},
708 {0.0, 0.0, 0.5, 0.5},
713 matrix4x4_t matrix_attenuationz =
716 {0.0, 0.0, 0.5, 0.5},
717 {0.0, 0.0, 0.0, 0.5},
718 {0.0, 0.0, 0.0, 0.5},
723 int *R_Shadow_ResizeShadowElements(int numtris)
725 // make sure shadowelements is big enough for this volume
726 if (maxshadowelements < numtris * 24)
728 maxshadowelements = numtris * 24;
730 Mem_Free(shadowelements);
731 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
733 return shadowelements;
736 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
738 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
739 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
740 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
742 if (r_shadow_buffer_leafpvs)
743 Mem_Free(r_shadow_buffer_leafpvs);
744 if (r_shadow_buffer_leaflist)
745 Mem_Free(r_shadow_buffer_leaflist);
746 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
747 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
748 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
750 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
752 if (r_shadow_buffer_surfacepvs)
753 Mem_Free(r_shadow_buffer_surfacepvs);
754 if (r_shadow_buffer_surfacelist)
755 Mem_Free(r_shadow_buffer_surfacelist);
756 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
757 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
758 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
762 void R_Shadow_PrepareShadowMark(int numtris)
764 // make sure shadowmark is big enough for this volume
765 if (maxshadowmark < numtris)
767 maxshadowmark = numtris;
769 Mem_Free(shadowmark);
771 Mem_Free(shadowmarklist);
772 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
773 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
777 // if shadowmarkcount wrapped we clear the array and adjust accordingly
778 if (shadowmarkcount == 0)
781 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
786 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)
789 int outtriangles = 0, outvertices = 0;
793 if (maxvertexupdate < innumvertices)
795 maxvertexupdate = innumvertices;
797 Mem_Free(vertexupdate);
799 Mem_Free(vertexremap);
800 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
801 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
805 if (vertexupdatenum == 0)
808 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
809 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
812 for (i = 0;i < numshadowmarktris;i++)
813 shadowmark[shadowmarktris[i]] = shadowmarkcount;
815 for (i = 0;i < numshadowmarktris;i++)
817 element = inelement3i + shadowmarktris[i] * 3;
818 // make sure the vertices are created
819 for (j = 0;j < 3;j++)
821 if (vertexupdate[element[j]] != vertexupdatenum)
823 float ratio, direction[3];
824 vertexupdate[element[j]] = vertexupdatenum;
825 vertexremap[element[j]] = outvertices;
826 vertex = invertex3f + element[j] * 3;
827 // project one copy of the vertex to the sphere radius of the light
828 // (FIXME: would projecting it to the light box be better?)
829 VectorSubtract(vertex, projectorigin, direction);
830 ratio = projectdistance / VectorLength(direction);
831 VectorCopy(vertex, outvertex3f);
832 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
839 for (i = 0;i < numshadowmarktris;i++)
841 int remappedelement[3];
843 const int *neighbortriangle;
845 markindex = shadowmarktris[i] * 3;
846 element = inelement3i + markindex;
847 neighbortriangle = inneighbor3i + markindex;
848 // output the front and back triangles
849 outelement3i[0] = vertexremap[element[0]];
850 outelement3i[1] = vertexremap[element[1]];
851 outelement3i[2] = vertexremap[element[2]];
852 outelement3i[3] = vertexremap[element[2]] + 1;
853 outelement3i[4] = vertexremap[element[1]] + 1;
854 outelement3i[5] = vertexremap[element[0]] + 1;
858 // output the sides (facing outward from this triangle)
859 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
861 remappedelement[0] = vertexremap[element[0]];
862 remappedelement[1] = vertexremap[element[1]];
863 outelement3i[0] = remappedelement[1];
864 outelement3i[1] = remappedelement[0];
865 outelement3i[2] = remappedelement[0] + 1;
866 outelement3i[3] = remappedelement[1];
867 outelement3i[4] = remappedelement[0] + 1;
868 outelement3i[5] = remappedelement[1] + 1;
873 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
875 remappedelement[1] = vertexremap[element[1]];
876 remappedelement[2] = vertexremap[element[2]];
877 outelement3i[0] = remappedelement[2];
878 outelement3i[1] = remappedelement[1];
879 outelement3i[2] = remappedelement[1] + 1;
880 outelement3i[3] = remappedelement[2];
881 outelement3i[4] = remappedelement[1] + 1;
882 outelement3i[5] = remappedelement[2] + 1;
887 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
889 remappedelement[0] = vertexremap[element[0]];
890 remappedelement[2] = vertexremap[element[2]];
891 outelement3i[0] = remappedelement[0];
892 outelement3i[1] = remappedelement[2];
893 outelement3i[2] = remappedelement[2] + 1;
894 outelement3i[3] = remappedelement[0];
895 outelement3i[4] = remappedelement[2] + 1;
896 outelement3i[5] = remappedelement[0] + 1;
903 *outnumvertices = outvertices;
907 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)
910 if (projectdistance < 0.1)
912 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
915 if (!numverts || !nummarktris)
917 // make sure shadowelements is big enough for this volume
918 if (maxshadowelements < nummarktris * 24)
919 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
920 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
921 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
924 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)
929 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
931 tend = firsttriangle + numtris;
932 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
933 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
934 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
936 // surface box entirely inside light box, no box cull
937 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
938 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
939 shadowmarklist[numshadowmark++] = t;
943 // surface box not entirely inside light box, cull each triangle
944 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
946 v[0] = invertex3f + e[0] * 3;
947 v[1] = invertex3f + e[1] * 3;
948 v[2] = invertex3f + e[2] * 3;
949 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
950 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
951 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
952 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
953 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
954 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
955 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
956 shadowmarklist[numshadowmark++] = t;
961 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
964 if (r_shadow_compilingrtlight)
966 // if we're compiling an rtlight, capture the mesh
967 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
970 memset(&m, 0, sizeof(m));
971 m.pointer_vertex = vertex3f;
973 GL_LockArrays(0, numvertices);
974 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
976 // decrement stencil if backface is behind depthbuffer
977 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
978 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
979 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
981 c_rt_shadowtris += numtriangles;
982 // increment stencil if frontface is behind depthbuffer
983 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
984 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
986 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
988 c_rt_shadowtris += numtriangles;
992 static void R_Shadow_MakeTextures(void)
995 float v[3], intensity;
997 R_FreeTexturePool(&r_shadow_texturepool);
998 r_shadow_texturepool = R_AllocTexturePool();
999 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
1000 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
1001 #define ATTEN2DSIZE 64
1002 #define ATTEN3DSIZE 32
1003 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
1004 for (y = 0;y < ATTEN2DSIZE;y++)
1006 for (x = 0;x < ATTEN2DSIZE;x++)
1008 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1009 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1011 intensity = 1.0f - sqrt(DotProduct(v, v));
1013 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1014 d = bound(0, intensity, 255);
1015 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1016 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1017 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1018 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1021 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1022 if (r_shadow_texture3d.integer)
1024 for (z = 0;z < ATTEN3DSIZE;z++)
1026 for (y = 0;y < ATTEN3DSIZE;y++)
1028 for (x = 0;x < ATTEN3DSIZE;x++)
1030 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1031 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1032 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1033 intensity = 1.0f - sqrt(DotProduct(v, v));
1035 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1036 d = bound(0, intensity, 255);
1037 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1038 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1039 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1040 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1044 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1049 void R_Shadow_ValidateCvars(void)
1051 if (r_shadow_texture3d.integer && !gl_texture3d)
1052 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1053 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1054 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1057 // light currently being rendered
1058 static rtlight_t *r_shadow_rtlight;
1059 // light filter cubemap being used by the light
1060 static rtexture_t *r_shadow_lightcubemap;
1062 // this is the location of the eye in entity space
1063 static vec3_t r_shadow_entityeyeorigin;
1064 // this is the location of the light in entity space
1065 static vec3_t r_shadow_entitylightorigin;
1066 // this transforms entity coordinates to light filter cubemap coordinates
1067 // (also often used for other purposes)
1068 static matrix4x4_t r_shadow_entitytolight;
1069 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1070 // of attenuation texturing in full 3D (Z result often ignored)
1071 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1072 // this transforms only the Z to S, and T is always 0.5
1073 static matrix4x4_t r_shadow_entitytoattenuationz;
1074 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1075 static vec3_t r_shadow_entitylightcolor;
1077 static int r_shadow_lightpermutation;
1078 static int r_shadow_lightprog;
1080 void R_Shadow_Stage_Begin(void)
1084 R_Shadow_ValidateCvars();
1086 if (!r_shadow_attenuation2dtexture
1087 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1088 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1089 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1090 R_Shadow_MakeTextures();
1092 memset(&m, 0, sizeof(m));
1093 GL_BlendFunc(GL_ONE, GL_ZERO);
1094 GL_DepthMask(false);
1097 GL_Color(0, 0, 0, 1);
1098 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1099 qglEnable(GL_CULL_FACE);
1100 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1101 r_shadowstage = R_SHADOWSTAGE_NONE;
1104 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1106 r_shadow_rtlight = rtlight;
1109 void R_Shadow_Stage_Reset(void)
1112 if (gl_support_stenciltwoside)
1113 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1114 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1116 qglUseProgramObjectARB(0);
1117 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1118 qglBegin(GL_TRIANGLES);
1122 memset(&m, 0, sizeof(m));
1126 void R_Shadow_Stage_StencilShadowVolumes(void)
1128 R_Shadow_Stage_Reset();
1129 GL_Color(1, 1, 1, 1);
1130 GL_ColorMask(0, 0, 0, 0);
1131 GL_BlendFunc(GL_ONE, GL_ZERO);
1132 GL_DepthMask(false);
1134 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1135 //if (r_shadow_shadow_polygonoffset.value != 0)
1137 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1138 // qglEnable(GL_POLYGON_OFFSET_FILL);
1141 // qglDisable(GL_POLYGON_OFFSET_FILL);
1142 qglDepthFunc(GL_LESS);
1143 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1144 qglEnable(GL_STENCIL_TEST);
1145 qglStencilFunc(GL_ALWAYS, 128, ~0);
1146 if (gl_ext_stenciltwoside.integer)
1148 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1149 qglDisable(GL_CULL_FACE);
1150 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1151 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1153 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1154 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1156 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1160 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1161 qglEnable(GL_CULL_FACE);
1163 // this is changed by every shadow render so its value here is unimportant
1164 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1166 GL_Clear(GL_STENCIL_BUFFER_BIT);
1170 void R_Shadow_Stage_Lighting(int stenciltest)
1173 R_Shadow_Stage_Reset();
1174 GL_BlendFunc(GL_ONE, GL_ONE);
1175 GL_DepthMask(false);
1177 qglPolygonOffset(0, 0);
1178 //qglDisable(GL_POLYGON_OFFSET_FILL);
1179 GL_Color(1, 1, 1, 1);
1180 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1181 qglDepthFunc(GL_EQUAL);
1182 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1183 qglEnable(GL_CULL_FACE);
1184 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1185 qglEnable(GL_STENCIL_TEST);
1187 qglDisable(GL_STENCIL_TEST);
1189 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1190 // only draw light where this geometry was already rendered AND the
1191 // stencil is 128 (values other than this mean shadow)
1192 qglStencilFunc(GL_EQUAL, 128, ~0);
1193 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1195 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1196 memset(&m, 0, sizeof(m));
1197 m.pointer_vertex = varray_vertex3f;
1198 m.pointer_texcoord[0] = varray_texcoord2f[0];
1199 m.pointer_texcoord3f[1] = varray_svector3f;
1200 m.pointer_texcoord3f[2] = varray_tvector3f;
1201 m.pointer_texcoord3f[3] = varray_normal3f;
1202 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1203 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1204 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1205 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1206 // TODO: support fog (after renderer is converted to texture fog)
1207 m.tex[4] = R_GetTexture(r_texture_white); // fog
1208 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1210 GL_BlendFunc(GL_ONE, GL_ONE);
1211 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1213 r_shadow_lightpermutation = 0;
1214 // only add a feature to the permutation if that permutation exists
1215 // (otherwise it might end up not using a shader at all, which looks
1216 // worse than using less features)
1217 if (r_shadow_rtlight->specularscale && r_shadow_gloss.integer >= 1 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1218 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1219 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1220 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1221 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1222 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1223 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1224 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1225 if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
1226 r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
1227 if (r_shadow_glsl_geforcefxlowquality.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
1228 r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
1229 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1230 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1231 // TODO: support fog (after renderer is converted to texture fog)
1232 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1234 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1236 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1237 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1238 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1240 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1241 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1243 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1244 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1245 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1247 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1249 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1251 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1252 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1255 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1256 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1258 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1261 void R_Shadow_Stage_VisibleShadowVolumes(void)
1263 R_Shadow_Stage_Reset();
1264 GL_BlendFunc(GL_ONE, GL_ONE);
1265 GL_DepthMask(false);
1266 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1267 qglPolygonOffset(0, 0);
1268 GL_Color(0.0, 0.0125, 0.1, 1);
1269 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1270 qglDepthFunc(GL_GEQUAL);
1271 qglCullFace(GL_FRONT); // this culls back
1272 qglDisable(GL_CULL_FACE);
1273 qglDisable(GL_STENCIL_TEST);
1274 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1277 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1279 R_Shadow_Stage_Reset();
1280 GL_BlendFunc(GL_ONE, GL_ONE);
1281 GL_DepthMask(false);
1282 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1283 qglPolygonOffset(0, 0);
1284 GL_Color(0.1, 0.0125, 0, 1);
1285 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1286 qglDepthFunc(GL_EQUAL);
1287 qglCullFace(GL_FRONT); // this culls back
1288 qglEnable(GL_CULL_FACE);
1290 qglEnable(GL_STENCIL_TEST);
1292 qglDisable(GL_STENCIL_TEST);
1293 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1296 void R_Shadow_Stage_End(void)
1298 R_Shadow_Stage_Reset();
1299 R_Shadow_Stage_ActiveLight(NULL);
1300 GL_BlendFunc(GL_ONE, GL_ZERO);
1303 qglPolygonOffset(0, 0);
1304 //qglDisable(GL_POLYGON_OFFSET_FILL);
1305 GL_Color(1, 1, 1, 1);
1306 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1307 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1308 qglDepthFunc(GL_LEQUAL);
1309 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1310 qglDisable(GL_STENCIL_TEST);
1311 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1312 if (gl_support_stenciltwoside)
1313 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1315 qglStencilFunc(GL_ALWAYS, 128, ~0);
1316 r_shadowstage = R_SHADOWSTAGE_NONE;
1319 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1321 int i, ix1, iy1, ix2, iy2;
1322 float x1, y1, x2, y2;
1325 mplane_t planes[11];
1326 float vertex3f[256*3];
1328 // if view is inside the light box, just say yes it's visible
1329 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1331 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1335 // create a temporary brush describing the area the light can affect in worldspace
1336 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1337 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1338 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1339 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1340 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1341 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1342 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1343 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1344 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1345 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1346 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1348 // turn the brush into a mesh
1349 memset(&mesh, 0, sizeof(rmesh_t));
1350 mesh.maxvertices = 256;
1351 mesh.vertex3f = vertex3f;
1352 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1353 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1355 // if that mesh is empty, the light is not visible at all
1356 if (!mesh.numvertices)
1359 if (!r_shadow_scissor.integer)
1362 // if that mesh is not empty, check what area of the screen it covers
1363 x1 = y1 = x2 = y2 = 0;
1365 for (i = 0;i < mesh.numvertices;i++)
1367 VectorCopy(mesh.vertex3f + i * 3, v);
1368 GL_TransformToScreen(v, v2);
1369 //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]);
1372 if (x1 > v2[0]) x1 = v2[0];
1373 if (x2 < v2[0]) x2 = v2[0];
1374 if (y1 > v2[1]) y1 = v2[1];
1375 if (y2 < v2[1]) y2 = v2[1];
1384 // now convert the scissor rectangle to integer screen coordinates
1389 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1391 // clamp it to the screen
1392 if (ix1 < r_view_x) ix1 = r_view_x;
1393 if (iy1 < r_view_y) iy1 = r_view_y;
1394 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1395 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1397 // if it is inside out, it's not visible
1398 if (ix2 <= ix1 || iy2 <= iy1)
1401 // the light area is visible, set up the scissor rectangle
1402 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1403 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1404 //qglEnable(GL_SCISSOR_TEST);
1409 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1411 float *color4f = varray_color4f;
1412 float dist, dot, intensity, v[3], n[3];
1413 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1415 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1416 if ((dist = DotProduct(v, v)) < 1)
1418 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1419 if ((dot = DotProduct(n, v)) > 0)
1422 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1423 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1424 VectorScale(lightcolor, intensity, color4f);
1429 VectorClear(color4f);
1435 VectorClear(color4f);
1441 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1443 float *color4f = varray_color4f;
1444 float dist, dot, intensity, v[3], n[3];
1445 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1447 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1448 if ((dist = fabs(v[2])) < 1)
1450 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1451 if ((dot = DotProduct(n, v)) > 0)
1453 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1454 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1455 VectorScale(lightcolor, intensity, color4f);
1460 VectorClear(color4f);
1466 VectorClear(color4f);
1472 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1474 float *color4f = varray_color4f;
1475 float dot, intensity, v[3], n[3];
1476 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1478 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1479 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1480 if ((dot = DotProduct(n, v)) > 0)
1482 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1483 VectorScale(lightcolor, intensity, color4f);
1488 VectorClear(color4f);
1494 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1496 float *color4f = varray_color4f;
1497 float dist, intensity, v[3];
1498 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1500 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1501 if ((dist = DotProduct(v, v)) < 1)
1504 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1505 VectorScale(lightcolor, intensity, color4f);
1510 VectorClear(color4f);
1516 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1518 float *color4f = varray_color4f;
1519 float dist, intensity, v[3];
1520 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1522 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1523 if ((dist = fabs(v[2])) < 1)
1525 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1526 VectorScale(lightcolor, intensity, color4f);
1531 VectorClear(color4f);
1537 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1538 #define USETEXMATRIX
1540 #ifndef USETEXMATRIX
1541 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1542 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1543 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1547 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1548 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1549 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1556 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1560 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1561 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1569 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)
1573 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1575 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1576 // the cubemap normalizes this for us
1577 out3f[0] = DotProduct(svector3f, lightdir);
1578 out3f[1] = DotProduct(tvector3f, lightdir);
1579 out3f[2] = DotProduct(normal3f, lightdir);
1583 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)
1586 float lightdir[3], eyedir[3], halfdir[3];
1587 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1589 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1590 VectorNormalize(lightdir);
1591 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1592 VectorNormalize(eyedir);
1593 VectorAdd(lightdir, eyedir, halfdir);
1594 // the cubemap normalizes this for us
1595 out3f[0] = DotProduct(svector3f, halfdir);
1596 out3f[1] = DotProduct(tvector3f, halfdir);
1597 out3f[2] = DotProduct(normal3f, halfdir);
1601 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)
1604 float color[3], color2[3], colorscale, specularscale;
1606 // FIXME: support MATERIALFLAG_NODEPTHTEST
1608 basetexture = r_texture_white;
1610 bumptexture = r_texture_blanknormalmap;
1612 lightcolorpants = vec3_origin;
1614 lightcolorshirt = vec3_origin;
1615 if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1616 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
1617 else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1619 glosstexture = r_texture_white;
1620 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
1624 glosstexture = r_texture_black;
1627 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1629 if (r_shadowstage == R_SHADOWSTAGE_VISIBLELIGHTING)
1632 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1633 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1634 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1636 // TODO: add direct pants/shirt rendering
1637 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1638 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1639 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1640 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1641 if (r_shadow_rtlight->ambientscale)
1643 colorscale = r_shadow_rtlight->ambientscale;
1644 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1647 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1650 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1653 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1658 VectorScale(lightcolorbase, colorscale, color2);
1659 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1662 if (r_shadow_rtlight->diffusescale)
1664 colorscale = r_shadow_rtlight->diffusescale;
1665 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1667 // 3/2 3D combine path (Geforce3, Radeon 8500)
1670 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1672 // 1/2/2 3D combine path (original Radeon)
1675 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1677 // 2/2 3D combine path (original Radeon)
1680 else if (r_textureunits.integer >= 4)
1682 // 4/2 2D combine path (Geforce3, Radeon 8500)
1687 // 2/2/2 2D combine path (any dot3 card)
1690 VectorScale(lightcolorbase, colorscale, color2);
1691 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1694 if (specularscale && glosstexture != r_texture_black)
1696 //if (gl_support_blendsquare)
1698 colorscale = specularscale;
1699 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1701 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1705 VectorScale(lightcolorbase, colorscale, color2);
1706 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1713 // TODO: add direct pants/shirt rendering
1714 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1715 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1716 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1717 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1718 if (r_shadow_rtlight->ambientscale)
1720 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
1721 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1724 if (r_shadow_rtlight->diffusescale)
1726 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
1727 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1733 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1734 memset(&m, 0, sizeof(m));
1735 m.pointer_vertex = vertex3f;
1737 GL_LockArrays(firstvertex, numvertices);
1738 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1739 GL_LockArrays(0, 0);
1743 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1745 // GLSL shader path (GFFX5200, Radeon 9500)
1746 R_Mesh_VertexPointer(vertex3f);
1747 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1748 R_Mesh_TexCoordPointer(1, 3, svector3f);
1749 R_Mesh_TexCoordPointer(2, 3, tvector3f);
1750 R_Mesh_TexCoordPointer(3, 3, normal3f);
1751 R_Mesh_TexBind(0, R_GetTexture(bumptexture));
1752 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1753 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1754 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1756 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1758 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1759 GL_LockArrays(firstvertex, numvertices);
1760 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1762 c_rt_lighttris += numtriangles;
1763 // TODO: add direct pants/shirt rendering
1764 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1766 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1767 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1768 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1770 c_rt_lighttris += numtriangles;
1772 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1774 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1775 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1776 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1778 c_rt_lighttris += numtriangles;
1780 GL_LockArrays(0, 0);
1782 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
1784 // TODO: add direct pants/shirt rendering
1785 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1786 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1787 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1788 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1789 if (r_shadow_rtlight->ambientscale)
1792 colorscale = r_shadow_rtlight->ambientscale;
1793 // colorscale accounts for how much we multiply the brightness
1796 // mult is how many times the final pass of the lighting will be
1797 // performed to get more brightness than otherwise possible.
1799 // Limit mult to 64 for sanity sake.
1800 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1802 // 3 3D combine path (Geforce3, Radeon 8500)
1803 memset(&m, 0, sizeof(m));
1804 m.pointer_vertex = vertex3f;
1805 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1807 m.pointer_texcoord3f[0] = vertex3f;
1808 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1810 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1811 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1813 m.tex[1] = R_GetTexture(basetexture);
1814 m.pointer_texcoord[1] = texcoord2f;
1815 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1817 m.pointer_texcoord3f[2] = vertex3f;
1818 m.texmatrix[2] = r_shadow_entitytolight;
1820 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1821 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1823 GL_BlendFunc(GL_ONE, GL_ONE);
1825 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1827 // 2 3D combine path (Geforce3, original Radeon)
1828 memset(&m, 0, sizeof(m));
1829 m.pointer_vertex = vertex3f;
1830 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1832 m.pointer_texcoord3f[0] = vertex3f;
1833 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1835 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1836 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1838 m.tex[1] = R_GetTexture(basetexture);
1839 m.pointer_texcoord[1] = texcoord2f;
1840 GL_BlendFunc(GL_ONE, GL_ONE);
1842 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1844 // 4 2D combine path (Geforce3, Radeon 8500)
1845 memset(&m, 0, sizeof(m));
1846 m.pointer_vertex = vertex3f;
1847 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1849 m.pointer_texcoord3f[0] = vertex3f;
1850 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1852 m.pointer_texcoord[0] = varray_texcoord2f[0];
1853 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1855 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1857 m.pointer_texcoord3f[1] = vertex3f;
1858 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1860 m.pointer_texcoord[1] = varray_texcoord2f[1];
1861 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1863 m.tex[2] = R_GetTexture(basetexture);
1864 m.pointer_texcoord[2] = texcoord2f;
1865 if (r_shadow_lightcubemap != r_texture_whitecube)
1867 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1869 m.pointer_texcoord3f[3] = vertex3f;
1870 m.texmatrix[3] = r_shadow_entitytolight;
1872 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1873 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1876 GL_BlendFunc(GL_ONE, GL_ONE);
1878 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1880 // 3 2D combine path (Geforce3, original Radeon)
1881 memset(&m, 0, sizeof(m));
1882 m.pointer_vertex = vertex3f;
1883 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1885 m.pointer_texcoord3f[0] = vertex3f;
1886 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1888 m.pointer_texcoord[0] = varray_texcoord2f[0];
1889 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1891 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1893 m.pointer_texcoord3f[1] = vertex3f;
1894 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1896 m.pointer_texcoord[1] = varray_texcoord2f[1];
1897 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1899 m.tex[2] = R_GetTexture(basetexture);
1900 m.pointer_texcoord[2] = texcoord2f;
1901 GL_BlendFunc(GL_ONE, GL_ONE);
1905 // 2/2/2 2D combine path (any dot3 card)
1906 memset(&m, 0, sizeof(m));
1907 m.pointer_vertex = vertex3f;
1908 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1910 m.pointer_texcoord3f[0] = vertex3f;
1911 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1913 m.pointer_texcoord[0] = varray_texcoord2f[0];
1914 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1916 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1918 m.pointer_texcoord3f[1] = vertex3f;
1919 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1921 m.pointer_texcoord[1] = varray_texcoord2f[1];
1922 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1925 GL_ColorMask(0,0,0,1);
1926 GL_BlendFunc(GL_ONE, GL_ZERO);
1927 GL_LockArrays(firstvertex, numvertices);
1928 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1929 GL_LockArrays(0, 0);
1931 c_rt_lighttris += numtriangles;
1933 memset(&m, 0, sizeof(m));
1934 m.pointer_vertex = vertex3f;
1935 m.tex[0] = R_GetTexture(basetexture);
1936 m.pointer_texcoord[0] = texcoord2f;
1937 if (r_shadow_lightcubemap != r_texture_whitecube)
1939 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1941 m.pointer_texcoord3f[1] = vertex3f;
1942 m.texmatrix[1] = r_shadow_entitytolight;
1944 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1945 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1948 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1950 // this final code is shared
1952 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1953 VectorScale(lightcolorbase, colorscale, color2);
1954 GL_LockArrays(firstvertex, numvertices);
1955 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1957 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1958 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1960 c_rt_lighttris += numtriangles;
1962 GL_LockArrays(0, 0);
1964 if (r_shadow_rtlight->diffusescale)
1967 colorscale = r_shadow_rtlight->diffusescale;
1968 // colorscale accounts for how much we multiply the brightness
1971 // mult is how many times the final pass of the lighting will be
1972 // performed to get more brightness than otherwise possible.
1974 // Limit mult to 64 for sanity sake.
1975 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1977 // 3/2 3D combine path (Geforce3, Radeon 8500)
1978 memset(&m, 0, sizeof(m));
1979 m.pointer_vertex = vertex3f;
1980 m.tex[0] = R_GetTexture(bumptexture);
1981 m.texcombinergb[0] = GL_REPLACE;
1982 m.pointer_texcoord[0] = texcoord2f;
1983 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1984 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1985 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1986 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);
1987 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1989 m.pointer_texcoord3f[2] = vertex3f;
1990 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1992 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1993 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1996 GL_ColorMask(0,0,0,1);
1997 GL_BlendFunc(GL_ONE, GL_ZERO);
1998 GL_LockArrays(firstvertex, numvertices);
1999 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2000 GL_LockArrays(0, 0);
2002 c_rt_lighttris += numtriangles;
2004 memset(&m, 0, sizeof(m));
2005 m.pointer_vertex = vertex3f;
2006 m.tex[0] = R_GetTexture(basetexture);
2007 m.pointer_texcoord[0] = texcoord2f;
2008 if (r_shadow_lightcubemap != r_texture_whitecube)
2010 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2012 m.pointer_texcoord3f[1] = vertex3f;
2013 m.texmatrix[1] = r_shadow_entitytolight;
2015 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2016 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2019 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2021 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
2023 // 1/2/2 3D combine path (original Radeon)
2024 memset(&m, 0, sizeof(m));
2025 m.pointer_vertex = vertex3f;
2026 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2028 m.pointer_texcoord3f[0] = vertex3f;
2029 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2031 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2032 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2035 GL_ColorMask(0,0,0,1);
2036 GL_BlendFunc(GL_ONE, GL_ZERO);
2037 GL_LockArrays(firstvertex, numvertices);
2038 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2039 GL_LockArrays(0, 0);
2041 c_rt_lighttris += numtriangles;
2043 memset(&m, 0, sizeof(m));
2044 m.pointer_vertex = vertex3f;
2045 m.tex[0] = R_GetTexture(bumptexture);
2046 m.texcombinergb[0] = GL_REPLACE;
2047 m.pointer_texcoord[0] = texcoord2f;
2048 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2049 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2050 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2051 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);
2053 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2054 GL_LockArrays(firstvertex, numvertices);
2055 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2056 GL_LockArrays(0, 0);
2058 c_rt_lighttris += numtriangles;
2060 memset(&m, 0, sizeof(m));
2061 m.pointer_vertex = vertex3f;
2062 m.tex[0] = R_GetTexture(basetexture);
2063 m.pointer_texcoord[0] = texcoord2f;
2064 if (r_shadow_lightcubemap != r_texture_whitecube)
2066 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2068 m.pointer_texcoord3f[1] = vertex3f;
2069 m.texmatrix[1] = r_shadow_entitytolight;
2071 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2072 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2075 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2077 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2079 // 2/2 3D combine path (original Radeon)
2080 memset(&m, 0, sizeof(m));
2081 m.pointer_vertex = vertex3f;
2082 m.tex[0] = R_GetTexture(bumptexture);
2083 m.texcombinergb[0] = GL_REPLACE;
2084 m.pointer_texcoord[0] = texcoord2f;
2085 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2086 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2087 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2088 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);
2090 GL_ColorMask(0,0,0,1);
2091 GL_BlendFunc(GL_ONE, GL_ZERO);
2092 GL_LockArrays(firstvertex, numvertices);
2093 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2094 GL_LockArrays(0, 0);
2096 c_rt_lighttris += numtriangles;
2098 memset(&m, 0, sizeof(m));
2099 m.pointer_vertex = vertex3f;
2100 m.tex[0] = R_GetTexture(basetexture);
2101 m.pointer_texcoord[0] = texcoord2f;
2102 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2104 m.pointer_texcoord3f[1] = vertex3f;
2105 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2107 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2108 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2110 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2112 else if (r_textureunits.integer >= 4)
2114 // 4/2 2D combine path (Geforce3, Radeon 8500)
2115 memset(&m, 0, sizeof(m));
2116 m.pointer_vertex = vertex3f;
2117 m.tex[0] = R_GetTexture(bumptexture);
2118 m.texcombinergb[0] = GL_REPLACE;
2119 m.pointer_texcoord[0] = texcoord2f;
2120 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2121 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2122 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2123 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);
2124 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2126 m.pointer_texcoord3f[2] = vertex3f;
2127 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2129 m.pointer_texcoord[2] = varray_texcoord2f[2];
2130 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2132 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2134 m.pointer_texcoord3f[3] = vertex3f;
2135 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2137 m.pointer_texcoord[3] = varray_texcoord2f[3];
2138 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2141 GL_ColorMask(0,0,0,1);
2142 GL_BlendFunc(GL_ONE, GL_ZERO);
2143 GL_LockArrays(firstvertex, numvertices);
2144 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2145 GL_LockArrays(0, 0);
2147 c_rt_lighttris += numtriangles;
2149 memset(&m, 0, sizeof(m));
2150 m.pointer_vertex = vertex3f;
2151 m.tex[0] = R_GetTexture(basetexture);
2152 m.pointer_texcoord[0] = texcoord2f;
2153 if (r_shadow_lightcubemap != r_texture_whitecube)
2155 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2157 m.pointer_texcoord3f[1] = vertex3f;
2158 m.texmatrix[1] = r_shadow_entitytolight;
2160 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2161 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2164 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2168 // 2/2/2 2D combine path (any dot3 card)
2169 memset(&m, 0, sizeof(m));
2170 m.pointer_vertex = vertex3f;
2171 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2173 m.pointer_texcoord3f[0] = vertex3f;
2174 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2176 m.pointer_texcoord[0] = varray_texcoord2f[0];
2177 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2179 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2181 m.pointer_texcoord3f[1] = vertex3f;
2182 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2184 m.pointer_texcoord[1] = varray_texcoord2f[1];
2185 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2188 GL_ColorMask(0,0,0,1);
2189 GL_BlendFunc(GL_ONE, GL_ZERO);
2190 GL_LockArrays(firstvertex, numvertices);
2191 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2192 GL_LockArrays(0, 0);
2194 c_rt_lighttris += numtriangles;
2196 memset(&m, 0, sizeof(m));
2197 m.pointer_vertex = vertex3f;
2198 m.tex[0] = R_GetTexture(bumptexture);
2199 m.texcombinergb[0] = GL_REPLACE;
2200 m.pointer_texcoord[0] = texcoord2f;
2201 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2202 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2203 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2204 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);
2206 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2207 GL_LockArrays(firstvertex, numvertices);
2208 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2209 GL_LockArrays(0, 0);
2211 c_rt_lighttris += numtriangles;
2213 memset(&m, 0, sizeof(m));
2214 m.pointer_vertex = vertex3f;
2215 m.tex[0] = R_GetTexture(basetexture);
2216 m.pointer_texcoord[0] = texcoord2f;
2217 if (r_shadow_lightcubemap != r_texture_whitecube)
2219 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2221 m.pointer_texcoord3f[1] = vertex3f;
2222 m.texmatrix[1] = r_shadow_entitytolight;
2224 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2225 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2228 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2230 // this final code is shared
2232 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2233 VectorScale(lightcolorbase, colorscale, color2);
2234 GL_LockArrays(firstvertex, numvertices);
2235 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2237 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2238 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2240 c_rt_lighttris += numtriangles;
2242 GL_LockArrays(0, 0);
2244 if (specularscale && glosstexture != r_texture_black)
2246 // FIXME: detect blendsquare!
2247 //if (gl_support_blendsquare)
2249 colorscale = specularscale;
2251 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2253 // 2/0/0/1/2 3D combine blendsquare path
2254 memset(&m, 0, sizeof(m));
2255 m.pointer_vertex = vertex3f;
2256 m.tex[0] = R_GetTexture(bumptexture);
2257 m.pointer_texcoord[0] = texcoord2f;
2258 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2259 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2260 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2261 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);
2263 GL_ColorMask(0,0,0,1);
2264 // this squares the result
2265 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2266 GL_LockArrays(firstvertex, numvertices);
2267 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2268 GL_LockArrays(0, 0);
2270 c_rt_lighttris += numtriangles;
2272 memset(&m, 0, sizeof(m));
2273 m.pointer_vertex = vertex3f;
2275 GL_LockArrays(firstvertex, numvertices);
2276 // square alpha in framebuffer a few times to make it shiny
2277 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2278 // these comments are a test run through this math for intensity 0.5
2279 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2280 // 0.25 * 0.25 = 0.0625 (this is another pass)
2281 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2282 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2284 c_rt_lighttris += numtriangles;
2285 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2287 c_rt_lighttris += numtriangles;
2288 GL_LockArrays(0, 0);
2290 memset(&m, 0, sizeof(m));
2291 m.pointer_vertex = vertex3f;
2292 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2294 m.pointer_texcoord3f[0] = vertex3f;
2295 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2297 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2298 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2301 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2302 GL_LockArrays(firstvertex, numvertices);
2303 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2304 GL_LockArrays(0, 0);
2306 c_rt_lighttris += numtriangles;
2308 memset(&m, 0, sizeof(m));
2309 m.pointer_vertex = vertex3f;
2310 m.tex[0] = R_GetTexture(glosstexture);
2311 m.pointer_texcoord[0] = texcoord2f;
2312 if (r_shadow_lightcubemap != r_texture_whitecube)
2314 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2316 m.pointer_texcoord3f[1] = vertex3f;
2317 m.texmatrix[1] = r_shadow_entitytolight;
2319 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2320 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2323 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2325 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2327 // 2/0/0/2 3D combine blendsquare path
2328 memset(&m, 0, sizeof(m));
2329 m.pointer_vertex = vertex3f;
2330 m.tex[0] = R_GetTexture(bumptexture);
2331 m.pointer_texcoord[0] = texcoord2f;
2332 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2333 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2334 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2335 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);
2337 GL_ColorMask(0,0,0,1);
2338 // this squares the result
2339 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2340 GL_LockArrays(firstvertex, numvertices);
2341 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2342 GL_LockArrays(0, 0);
2344 c_rt_lighttris += numtriangles;
2346 memset(&m, 0, sizeof(m));
2347 m.pointer_vertex = vertex3f;
2349 GL_LockArrays(firstvertex, numvertices);
2350 // square alpha in framebuffer a few times to make it shiny
2351 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2352 // these comments are a test run through this math for intensity 0.5
2353 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2354 // 0.25 * 0.25 = 0.0625 (this is another pass)
2355 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2356 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2358 c_rt_lighttris += numtriangles;
2359 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2361 c_rt_lighttris += numtriangles;
2362 GL_LockArrays(0, 0);
2364 memset(&m, 0, sizeof(m));
2365 m.pointer_vertex = vertex3f;
2366 m.tex[0] = R_GetTexture(glosstexture);
2367 m.pointer_texcoord[0] = texcoord2f;
2368 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2370 m.pointer_texcoord3f[1] = vertex3f;
2371 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2373 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2374 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2376 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2380 // 2/0/0/2/2 2D combine blendsquare path
2381 memset(&m, 0, sizeof(m));
2382 m.pointer_vertex = vertex3f;
2383 m.tex[0] = R_GetTexture(bumptexture);
2384 m.pointer_texcoord[0] = texcoord2f;
2385 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2386 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2387 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2388 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);
2390 GL_ColorMask(0,0,0,1);
2391 // this squares the result
2392 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2393 GL_LockArrays(firstvertex, numvertices);
2394 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2395 GL_LockArrays(0, 0);
2397 c_rt_lighttris += numtriangles;
2399 memset(&m, 0, sizeof(m));
2400 m.pointer_vertex = vertex3f;
2402 GL_LockArrays(firstvertex, numvertices);
2403 // square alpha in framebuffer a few times to make it shiny
2404 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2405 // these comments are a test run through this math for intensity 0.5
2406 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2407 // 0.25 * 0.25 = 0.0625 (this is another pass)
2408 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2409 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2411 c_rt_lighttris += numtriangles;
2412 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2414 c_rt_lighttris += numtriangles;
2415 GL_LockArrays(0, 0);
2417 memset(&m, 0, sizeof(m));
2418 m.pointer_vertex = vertex3f;
2419 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2421 m.pointer_texcoord3f[0] = vertex3f;
2422 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2424 m.pointer_texcoord[0] = varray_texcoord2f[0];
2425 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2427 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2429 m.pointer_texcoord3f[1] = vertex3f;
2430 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2432 m.pointer_texcoord[1] = varray_texcoord2f[1];
2433 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2436 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2437 GL_LockArrays(firstvertex, numvertices);
2438 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2439 GL_LockArrays(0, 0);
2441 c_rt_lighttris += numtriangles;
2443 memset(&m, 0, sizeof(m));
2444 m.pointer_vertex = vertex3f;
2445 m.tex[0] = R_GetTexture(glosstexture);
2446 m.pointer_texcoord[0] = texcoord2f;
2447 if (r_shadow_lightcubemap != r_texture_whitecube)
2449 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2451 m.pointer_texcoord3f[1] = vertex3f;
2452 m.texmatrix[1] = r_shadow_entitytolight;
2454 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2455 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2458 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2461 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2462 VectorScale(lightcolorbase, colorscale, color2);
2463 GL_LockArrays(firstvertex, numvertices);
2464 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2466 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2467 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2469 c_rt_lighttris += numtriangles;
2471 GL_LockArrays(0, 0);
2475 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
2477 // TODO: add direct pants/shirt rendering
2478 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2479 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
2480 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2481 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
2482 if (r_shadow_rtlight->ambientscale)
2484 GL_BlendFunc(GL_ONE, GL_ONE);
2485 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
2486 memset(&m, 0, sizeof(m));
2487 m.pointer_vertex = vertex3f;
2488 m.tex[0] = R_GetTexture(basetexture);
2489 m.pointer_texcoord[0] = texcoord2f;
2490 if (r_textureunits.integer >= 2)
2493 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2495 m.pointer_texcoord3f[1] = vertex3f;
2496 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2498 m.pointer_texcoord[1] = varray_texcoord2f[1];
2499 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2501 if (r_textureunits.integer >= 3)
2503 // Geforce3/Radeon class but not using dot3
2504 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2506 m.pointer_texcoord3f[2] = vertex3f;
2507 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2509 m.pointer_texcoord[2] = varray_texcoord2f[2];
2510 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2514 if (r_textureunits.integer >= 3)
2515 m.pointer_color = NULL;
2517 m.pointer_color = varray_color4f;
2519 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2521 color[0] = bound(0, color2[0], 1);
2522 color[1] = bound(0, color2[1], 1);
2523 color[2] = bound(0, color2[2], 1);
2524 if (r_textureunits.integer >= 3)
2525 GL_Color(color[0], color[1], color[2], 1);
2526 else if (r_textureunits.integer >= 2)
2527 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2529 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2530 GL_LockArrays(firstvertex, numvertices);
2531 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2532 GL_LockArrays(0, 0);
2534 c_rt_lighttris += numtriangles;
2537 if (r_shadow_rtlight->diffusescale)
2539 GL_BlendFunc(GL_ONE, GL_ONE);
2540 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
2541 memset(&m, 0, sizeof(m));
2542 m.pointer_vertex = vertex3f;
2543 m.pointer_color = varray_color4f;
2544 m.tex[0] = R_GetTexture(basetexture);
2545 m.pointer_texcoord[0] = texcoord2f;
2546 if (r_textureunits.integer >= 2)
2549 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2551 m.pointer_texcoord3f[1] = vertex3f;
2552 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2554 m.pointer_texcoord[1] = varray_texcoord2f[1];
2555 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2557 if (r_textureunits.integer >= 3)
2559 // Geforce3/Radeon class but not using dot3
2560 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2562 m.pointer_texcoord3f[2] = vertex3f;
2563 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2565 m.pointer_texcoord[2] = varray_texcoord2f[2];
2566 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2571 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2573 color[0] = bound(0, color2[0], 1);
2574 color[1] = bound(0, color2[1], 1);
2575 color[2] = bound(0, color2[2], 1);
2576 if (r_textureunits.integer >= 3)
2577 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2578 else if (r_textureunits.integer >= 2)
2579 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2581 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2582 GL_LockArrays(firstvertex, numvertices);
2583 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2584 GL_LockArrays(0, 0);
2586 c_rt_lighttris += numtriangles;
2592 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2596 R_RTLight_Uncompile(rtlight);
2597 memset(rtlight, 0, sizeof(*rtlight));
2599 VectorCopy(light->origin, rtlight->shadoworigin);
2600 VectorCopy(light->color, rtlight->color);
2601 rtlight->radius = light->radius;
2602 //rtlight->cullradius = rtlight->radius;
2603 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2604 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2605 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2606 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2607 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2608 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2609 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2610 rtlight->cubemapname[0] = 0;
2611 if (light->cubemapname[0])
2612 strcpy(rtlight->cubemapname, light->cubemapname);
2613 else if (light->cubemapnum > 0)
2614 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2615 rtlight->shadow = light->shadow;
2616 rtlight->corona = light->corona;
2617 rtlight->style = light->style;
2618 rtlight->isstatic = isstatic;
2619 rtlight->coronasizescale = light->coronasizescale;
2620 rtlight->ambientscale = light->ambientscale;
2621 rtlight->diffusescale = light->diffusescale;
2622 rtlight->specularscale = light->specularscale;
2623 rtlight->flags = light->flags;
2624 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2625 // ConcatScale won't work here because this needs to scale rotate and
2626 // translate, not just rotate
2627 scale = 1.0f / rtlight->radius;
2628 for (k = 0;k < 3;k++)
2629 for (j = 0;j < 4;j++)
2630 rtlight->matrix_worldtolight.m[k][j] *= scale;
2632 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2633 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2634 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2635 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2638 // compiles rtlight geometry
2639 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2640 void R_RTLight_Compile(rtlight_t *rtlight)
2642 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2643 entity_render_t *ent = r_refdef.worldentity;
2644 model_t *model = r_refdef.worldmodel;
2647 // compile the light
2648 rtlight->compiled = true;
2649 rtlight->static_numleafs = 0;
2650 rtlight->static_numleafpvsbytes = 0;
2651 rtlight->static_leaflist = NULL;
2652 rtlight->static_leafpvs = NULL;
2653 rtlight->static_numsurfaces = 0;
2654 rtlight->static_surfacelist = NULL;
2655 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2656 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2657 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2658 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2659 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2660 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2662 if (model && model->GetLightInfo)
2664 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2665 r_shadow_compilingrtlight = rtlight;
2666 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2667 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);
2668 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2669 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2670 rtlight->static_numleafs = numleafs;
2671 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2672 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2673 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2674 rtlight->static_numsurfaces = numsurfaces;
2675 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2677 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2678 if (numleafpvsbytes)
2679 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2681 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2682 if (model->DrawShadowVolume && rtlight->shadow)
2684 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2685 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2686 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2688 if (model->DrawLight)
2690 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2691 model->DrawLight(ent, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
2692 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2694 // switch back to rendering when DrawShadowVolume or DrawLight is called
2695 r_shadow_compilingrtlight = NULL;
2699 // use smallest available cullradius - box radius or light radius
2700 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2701 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2705 if (rtlight->static_meshchain_shadow)
2708 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2711 shadowtris += mesh->numtriangles;
2717 if (rtlight->static_meshchain_light)
2720 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2723 lighttris += mesh->numtriangles;
2727 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);
2730 void R_RTLight_Uncompile(rtlight_t *rtlight)
2732 if (rtlight->compiled)
2734 if (rtlight->static_meshchain_shadow)
2735 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2736 rtlight->static_meshchain_shadow = NULL;
2737 if (rtlight->static_meshchain_light)
2738 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2739 rtlight->static_meshchain_light = NULL;
2740 // these allocations are grouped
2741 if (rtlight->static_leaflist)
2742 Mem_Free(rtlight->static_leaflist);
2743 rtlight->static_numleafs = 0;
2744 rtlight->static_numleafpvsbytes = 0;
2745 rtlight->static_leaflist = NULL;
2746 rtlight->static_leafpvs = NULL;
2747 rtlight->static_numsurfaces = 0;
2748 rtlight->static_surfacelist = NULL;
2749 rtlight->compiled = false;
2753 void R_Shadow_UncompileWorldLights(void)
2756 for (light = r_shadow_worldlightchain;light;light = light->next)
2757 R_RTLight_Uncompile(&light->rtlight);
2760 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2762 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2763 vec_t relativeshadowradius;
2764 if (ent == r_refdef.worldentity)
2766 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2769 R_Mesh_Matrix(&ent->matrix);
2770 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2772 R_Mesh_VertexPointer(mesh->vertex3f);
2773 GL_LockArrays(0, mesh->numverts);
2774 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2776 // decrement stencil if backface is behind depthbuffer
2777 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2778 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2779 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2780 c_rtcached_shadowmeshes++;
2781 c_rtcached_shadowtris += mesh->numtriangles;
2782 // increment stencil if frontface is behind depthbuffer
2783 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2784 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2786 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2787 c_rtcached_shadowmeshes++;
2788 c_rtcached_shadowtris += mesh->numtriangles;
2789 GL_LockArrays(0, 0);
2792 else if (numsurfaces)
2794 R_Mesh_Matrix(&ent->matrix);
2795 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2800 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2801 relativeshadowradius = rtlight->radius / ent->scale;
2802 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2803 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2804 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2805 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2806 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2807 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2808 R_Mesh_Matrix(&ent->matrix);
2809 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2813 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2816 // set up properties for rendering light onto this entity
2817 r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2818 r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2819 r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2820 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2821 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2822 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2823 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2824 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2825 R_Mesh_Matrix(&ent->matrix);
2826 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2828 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2829 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2830 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2831 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2833 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2836 if (ent == r_refdef.worldentity)
2838 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2840 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2841 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);
2844 ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2847 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2850 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2855 int numleafs, numsurfaces;
2856 int *leaflist, *surfacelist;
2858 int numlightentities;
2859 int numshadowentities;
2860 entity_render_t *lightentities[MAX_EDICTS];
2861 entity_render_t *shadowentities[MAX_EDICTS];
2863 // skip lights that don't light (corona only lights)
2864 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2867 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2868 VectorScale(rtlight->color, f, lightcolor);
2869 if (VectorLength2(lightcolor) < 0.01)
2872 if (rtlight->selected)
2874 f = 2 + sin(realtime * M_PI * 4.0);
2875 VectorScale(lightcolor, f, lightcolor);
2879 // loading is done before visibility checks because loading should happen
2880 // all at once at the start of a level, not when it stalls gameplay.
2881 // (especially important to benchmarks)
2883 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2884 R_RTLight_Compile(rtlight);
2886 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2888 // if the light box is offscreen, skip it
2889 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2892 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2894 // compiled light, world available and can receive realtime lighting
2895 // retrieve leaf information
2896 numleafs = rtlight->static_numleafs;
2897 leaflist = rtlight->static_leaflist;
2898 leafpvs = rtlight->static_leafpvs;
2899 numsurfaces = rtlight->static_numsurfaces;
2900 surfacelist = rtlight->static_surfacelist;
2902 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2904 // dynamic light, world available and can receive realtime lighting
2905 // calculate lit surfaces and leafs
2906 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2907 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);
2908 leaflist = r_shadow_buffer_leaflist;
2909 leafpvs = r_shadow_buffer_leafpvs;
2910 surfacelist = r_shadow_buffer_surfacelist;
2911 // if the reduced leaf bounds are offscreen, skip it
2912 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2924 // check if light is illuminating any visible leafs
2927 for (i = 0;i < numleafs;i++)
2928 if (r_worldleafvisible[leaflist[i]])
2933 // set up a scissor rectangle for this light
2934 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2937 numlightentities = 0;
2939 lightentities[numlightentities++] = r_refdef.worldentity;
2940 numshadowentities = 0;
2942 shadowentities[numshadowentities++] = r_refdef.worldentity;
2943 if (r_drawentities.integer)
2945 for (i = 0;i < r_refdef.numentities;i++)
2947 entity_render_t *ent = r_refdef.entities[i];
2948 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2950 && !(ent->flags & RENDER_TRANSPARENT)
2951 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2953 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2954 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2955 shadowentities[numshadowentities++] = ent;
2956 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2957 lightentities[numlightentities++] = ent;
2962 // return if there's nothing at all to light
2963 if (!numlightentities)
2966 R_Shadow_Stage_ActiveLight(rtlight);
2970 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2973 R_Shadow_Stage_StencilShadowVolumes();
2974 for (i = 0;i < numshadowentities;i++)
2975 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2978 if (numlightentities && !visible)
2980 R_Shadow_Stage_Lighting(usestencil);
2981 for (i = 0;i < numlightentities;i++)
2982 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2985 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2987 R_Shadow_Stage_VisibleShadowVolumes();
2988 for (i = 0;i < numshadowentities;i++)
2989 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2992 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2994 R_Shadow_Stage_VisibleLighting(usestencil);
2995 for (i = 0;i < numlightentities;i++)
2996 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
3000 void R_ShadowVolumeLighting(qboolean visible)
3005 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3006 R_Shadow_EditLights_Reload_f();
3008 R_Shadow_Stage_Begin();
3010 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3011 if (r_shadow_debuglight.integer >= 0)
3013 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3014 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3015 R_DrawRTLight(&light->rtlight, visible);
3018 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3019 if (light->flags & flag)
3020 R_DrawRTLight(&light->rtlight, visible);
3022 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
3023 R_DrawRTLight(&light->rtlight, visible);
3025 R_Shadow_Stage_End();
3028 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3029 typedef struct suffixinfo_s
3032 qboolean flipx, flipy, flipdiagonal;
3035 static suffixinfo_t suffix[3][6] =
3038 {"px", false, false, false},
3039 {"nx", false, false, false},
3040 {"py", false, false, false},
3041 {"ny", false, false, false},
3042 {"pz", false, false, false},
3043 {"nz", false, false, false}
3046 {"posx", false, false, false},
3047 {"negx", false, false, false},
3048 {"posy", false, false, false},
3049 {"negy", false, false, false},
3050 {"posz", false, false, false},
3051 {"negz", false, false, false}
3054 {"rt", true, false, true},
3055 {"lf", false, true, true},
3056 {"ft", true, true, false},
3057 {"bk", false, false, false},
3058 {"up", true, false, true},
3059 {"dn", true, false, true}
3063 static int componentorder[4] = {0, 1, 2, 3};
3065 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3067 int i, j, cubemapsize;
3068 qbyte *cubemappixels, *image_rgba;
3069 rtexture_t *cubemaptexture;
3071 // must start 0 so the first loadimagepixels has no requested width/height
3073 cubemappixels = NULL;
3074 cubemaptexture = NULL;
3075 // keep trying different suffix groups (posx, px, rt) until one loads
3076 for (j = 0;j < 3 && !cubemappixels;j++)
3078 // load the 6 images in the suffix group
3079 for (i = 0;i < 6;i++)
3081 // generate an image name based on the base and and suffix
3082 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3084 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3086 // an image loaded, make sure width and height are equal
3087 if (image_width == image_height)
3089 // if this is the first image to load successfully, allocate the cubemap memory
3090 if (!cubemappixels && image_width >= 1)
3092 cubemapsize = image_width;
3093 // note this clears to black, so unavailable sides are black
3094 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3096 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3098 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);
3101 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3103 Mem_Free(image_rgba);
3107 // if a cubemap loaded, upload it
3110 if (!r_shadow_filters_texturepool)
3111 r_shadow_filters_texturepool = R_AllocTexturePool();
3112 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3113 Mem_Free(cubemappixels);
3117 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3118 for (j = 0;j < 3;j++)
3119 for (i = 0;i < 6;i++)
3120 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3121 Con_Print(" and was unable to find any of them.\n");
3123 return cubemaptexture;
3126 rtexture_t *R_Shadow_Cubemap(const char *basename)
3129 for (i = 0;i < numcubemaps;i++)
3130 if (!strcasecmp(cubemaps[i].basename, basename))
3131 return cubemaps[i].texture;
3132 if (i >= MAX_CUBEMAPS)
3133 return r_texture_whitecube;
3135 strcpy(cubemaps[i].basename, basename);
3136 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3137 return cubemaps[i].texture;
3140 void R_Shadow_FreeCubemaps(void)
3143 R_FreeTexturePool(&r_shadow_filters_texturepool);
3146 dlight_t *R_Shadow_NewWorldLight(void)
3149 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3150 light->next = r_shadow_worldlightchain;
3151 r_shadow_worldlightchain = light;
3155 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)
3157 VectorCopy(origin, light->origin);
3158 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3159 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3160 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3161 light->color[0] = max(color[0], 0);
3162 light->color[1] = max(color[1], 0);
3163 light->color[2] = max(color[2], 0);
3164 light->radius = max(radius, 0);
3165 light->style = style;
3166 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3168 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3171 light->shadow = shadowenable;
3172 light->corona = corona;
3175 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3176 light->coronasizescale = coronasizescale;
3177 light->ambientscale = ambientscale;
3178 light->diffusescale = diffusescale;
3179 light->specularscale = specularscale;
3180 light->flags = flags;
3181 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3183 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3186 void R_Shadow_FreeWorldLight(dlight_t *light)
3188 dlight_t **lightpointer;
3189 R_RTLight_Uncompile(&light->rtlight);
3190 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3191 if (*lightpointer != light)
3192 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3193 *lightpointer = light->next;
3197 void R_Shadow_ClearWorldLights(void)
3199 while (r_shadow_worldlightchain)
3200 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3201 r_shadow_selectedlight = NULL;
3202 R_Shadow_FreeCubemaps();
3205 void R_Shadow_SelectLight(dlight_t *light)
3207 if (r_shadow_selectedlight)
3208 r_shadow_selectedlight->selected = false;
3209 r_shadow_selectedlight = light;
3210 if (r_shadow_selectedlight)
3211 r_shadow_selectedlight->selected = true;
3214 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3216 float scale = r_editlights_cursorgrid.value * 0.5f;
3217 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);
3220 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3223 const dlight_t *light;
3226 if (light->selected)
3227 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3230 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);
3233 void R_Shadow_DrawLightSprites(void)
3239 for (i = 0;i < 5;i++)
3241 lighttextures[i] = NULL;
3242 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3243 lighttextures[i] = pic->tex;
3246 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3247 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3248 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3251 void R_Shadow_SelectLightInView(void)
3253 float bestrating, rating, temp[3];
3254 dlight_t *best, *light;
3257 for (light = r_shadow_worldlightchain;light;light = light->next)
3259 VectorSubtract(light->origin, r_vieworigin, temp);
3260 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3263 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3264 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3266 bestrating = rating;
3271 R_Shadow_SelectLight(best);
3274 void R_Shadow_LoadWorldLights(void)
3276 int n, a, style, shadow, flags;
3277 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3278 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3279 if (r_refdef.worldmodel == NULL)
3281 Con_Print("No map loaded.\n");
3284 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3285 strlcat (name, ".rtlights", sizeof (name));
3286 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3296 for (;COM_Parse(t, true) && strcmp(
3297 if (COM_Parse(t, true))
3299 if (com_token[0] == '!')
3302 origin[0] = atof(com_token+1);
3305 origin[0] = atof(com_token);
3310 while (*s && *s != '\n' && *s != '\r')
3316 // check for modifier flags
3323 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);
3326 flags = LIGHTFLAG_REALTIMEMODE;
3334 coronasizescale = 0.25f;
3336 VectorClear(angles);
3339 if (a < 9 || !strcmp(cubemapname, "\"\""))
3341 // remove quotes on cubemapname
3342 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3344 cubemapname[strlen(cubemapname)-1] = 0;
3345 strcpy(cubemapname, cubemapname + 1);
3349 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);
3352 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3360 Con_Printf("invalid rtlights file \"%s\"\n", name);
3361 Mem_Free(lightsstring);
3365 void R_Shadow_SaveWorldLights(void)
3368 int bufchars, bufmaxchars;
3370 char name[MAX_QPATH];
3372 if (!r_shadow_worldlightchain)
3374 if (r_refdef.worldmodel == NULL)
3376 Con_Print("No map loaded.\n");
3379 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3380 strlcat (name, ".rtlights", sizeof (name));
3381 bufchars = bufmaxchars = 0;
3383 for (light = r_shadow_worldlightchain;light;light = light->next)
3385 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3386 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, light->color[0], light->color[1], light->color[2], 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);
3387 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3388 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, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3390 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, light->color[0], light->color[1], light->color[2], light->style);
3391 if (bufchars + (int) strlen(line) > bufmaxchars)
3393 bufmaxchars = bufchars + strlen(line) + 2048;
3395 buf = Mem_Alloc(tempmempool, bufmaxchars);
3399 memcpy(buf, oldbuf, bufchars);
3405 memcpy(buf + bufchars, line, strlen(line));
3406 bufchars += strlen(line);
3410 FS_WriteFile(name, buf, bufchars);
3415 void R_Shadow_LoadLightsFile(void)
3418 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3419 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3420 if (r_refdef.worldmodel == NULL)
3422 Con_Print("No map loaded.\n");
3425 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3426 strlcat (name, ".lights", sizeof (name));
3427 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3435 while (*s && *s != '\n' && *s != '\r')
3441 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);
3445 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);
3448 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3449 radius = bound(15, radius, 4096);
3450 VectorScale(color, (2.0f / (8388608.0f)), color);
3451 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3459 Con_Printf("invalid lights file \"%s\"\n", name);
3460 Mem_Free(lightsstring);
3464 // tyrlite/hmap2 light types in the delay field
3465 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3467 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3469 int entnum, style, islight, skin, pflags, effects, type, n;
3472 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3473 char key[256], value[1024];
3475 if (r_refdef.worldmodel == NULL)
3477 Con_Print("No map loaded.\n");
3480 // try to load a .ent file first
3481 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3482 strlcat (key, ".ent", sizeof (key));
3483 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true);
3484 // and if that is not found, fall back to the bsp file entity string
3486 data = r_refdef.worldmodel->brush.entities;
3489 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3491 type = LIGHTTYPE_MINUSX;
3492 origin[0] = origin[1] = origin[2] = 0;
3493 originhack[0] = originhack[1] = originhack[2] = 0;
3494 angles[0] = angles[1] = angles[2] = 0;
3495 color[0] = color[1] = color[2] = 1;
3496 light[0] = light[1] = light[2] = 1;light[3] = 300;
3497 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3507 if (!COM_ParseToken(&data, false))
3509 if (com_token[0] == '}')
3510 break; // end of entity
3511 if (com_token[0] == '_')
3512 strcpy(key, com_token + 1);
3514 strcpy(key, com_token);
3515 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3516 key[strlen(key)-1] = 0;
3517 if (!COM_ParseToken(&data, false))
3519 strcpy(value, com_token);
3521 // now that we have the key pair worked out...
3522 if (!strcmp("light", key))
3524 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3528 light[0] = vec[0] * (1.0f / 256.0f);
3529 light[1] = vec[0] * (1.0f / 256.0f);
3530 light[2] = vec[0] * (1.0f / 256.0f);
3536 light[0] = vec[0] * (1.0f / 255.0f);
3537 light[1] = vec[1] * (1.0f / 255.0f);
3538 light[2] = vec[2] * (1.0f / 255.0f);
3542 else if (!strcmp("delay", key))
3544 else if (!strcmp("origin", key))
3545 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3546 else if (!strcmp("angle", key))
3547 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3548 else if (!strcmp("angles", key))
3549 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3550 else if (!strcmp("color", key))
3551 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3552 else if (!strcmp("wait", key))
3553 fadescale = atof(value);
3554 else if (!strcmp("classname", key))
3556 if (!strncmp(value, "light", 5))
3559 if (!strcmp(value, "light_fluoro"))
3564 overridecolor[0] = 1;
3565 overridecolor[1] = 1;
3566 overridecolor[2] = 1;
3568 if (!strcmp(value, "light_fluorospark"))
3573 overridecolor[0] = 1;
3574 overridecolor[1] = 1;
3575 overridecolor[2] = 1;
3577 if (!strcmp(value, "light_globe"))
3582 overridecolor[0] = 1;
3583 overridecolor[1] = 0.8;
3584 overridecolor[2] = 0.4;
3586 if (!strcmp(value, "light_flame_large_yellow"))
3591 overridecolor[0] = 1;
3592 overridecolor[1] = 0.5;
3593 overridecolor[2] = 0.1;
3595 if (!strcmp(value, "light_flame_small_yellow"))
3600 overridecolor[0] = 1;
3601 overridecolor[1] = 0.5;
3602 overridecolor[2] = 0.1;
3604 if (!strcmp(value, "light_torch_small_white"))
3609 overridecolor[0] = 1;
3610 overridecolor[1] = 0.5;
3611 overridecolor[2] = 0.1;
3613 if (!strcmp(value, "light_torch_small_walltorch"))
3618 overridecolor[0] = 1;
3619 overridecolor[1] = 0.5;
3620 overridecolor[2] = 0.1;
3624 else if (!strcmp("style", key))
3625 style = atoi(value);
3626 else if (r_refdef.worldmodel->type == mod_brushq3)
3628 if (!strcmp("scale", key))
3629 lightscale = atof(value);
3630 if (!strcmp("fade", key))
3631 fadescale = atof(value);
3633 else if (!strcmp("skin", key))
3634 skin = (int)atof(value);
3635 else if (!strcmp("pflags", key))
3636 pflags = (int)atof(value);
3637 else if (!strcmp("effects", key))
3638 effects = (int)atof(value);
3642 if (lightscale <= 0)
3646 if (color[0] == color[1] && color[0] == color[2])
3648 color[0] *= overridecolor[0];
3649 color[1] *= overridecolor[1];
3650 color[2] *= overridecolor[2];
3652 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3653 color[0] = color[0] * light[0];
3654 color[1] = color[1] * light[1];
3655 color[2] = color[2] * light[2];
3658 case LIGHTTYPE_MINUSX:
3660 case LIGHTTYPE_RECIPX:
3662 VectorScale(color, (1.0f / 16.0f), color);
3664 case LIGHTTYPE_RECIPXX:
3666 VectorScale(color, (1.0f / 16.0f), color);
3669 case LIGHTTYPE_NONE:
3673 case LIGHTTYPE_MINUSXX:
3676 VectorAdd(origin, originhack, origin);
3678 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);
3681 Mem_Free(entfiledata);
3685 void R_Shadow_SetCursorLocationForView(void)
3688 vec3_t dest, endpos;
3690 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3691 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3692 if (trace.fraction < 1)
3694 dist = trace.fraction * r_editlights_cursordistance.value;
3695 push = r_editlights_cursorpushback.value;
3699 VectorMA(trace.endpos, push, r_viewforward, endpos);
3700 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3702 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3703 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3704 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3707 void R_Shadow_UpdateWorldLightSelection(void)
3709 if (r_editlights.integer)
3711 R_Shadow_SetCursorLocationForView();
3712 R_Shadow_SelectLightInView();
3713 R_Shadow_DrawLightSprites();
3716 R_Shadow_SelectLight(NULL);
3719 void R_Shadow_EditLights_Clear_f(void)
3721 R_Shadow_ClearWorldLights();
3724 void R_Shadow_EditLights_Reload_f(void)
3726 if (!r_refdef.worldmodel)
3728 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3729 R_Shadow_ClearWorldLights();
3730 R_Shadow_LoadWorldLights();
3731 if (r_shadow_worldlightchain == NULL)
3733 R_Shadow_LoadLightsFile();
3734 if (r_shadow_worldlightchain == NULL)
3735 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3739 void R_Shadow_EditLights_Save_f(void)
3741 if (!r_refdef.worldmodel)
3743 R_Shadow_SaveWorldLights();
3746 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3748 R_Shadow_ClearWorldLights();
3749 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3752 void R_Shadow_EditLights_ImportLightsFile_f(void)
3754 R_Shadow_ClearWorldLights();
3755 R_Shadow_LoadLightsFile();
3758 void R_Shadow_EditLights_Spawn_f(void)
3761 if (!r_editlights.integer)
3763 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3766 if (Cmd_Argc() != 1)
3768 Con_Print("r_editlights_spawn does not take parameters\n");
3771 color[0] = color[1] = color[2] = 1;
3772 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3775 void R_Shadow_EditLights_Edit_f(void)
3777 vec3_t origin, angles, color;
3778 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3779 int style, shadows, flags, normalmode, realtimemode;
3780 char cubemapname[1024];
3781 if (!r_editlights.integer)
3783 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3786 if (!r_shadow_selectedlight)
3788 Con_Print("No selected light.\n");
3791 VectorCopy(r_shadow_selectedlight->origin, origin);
3792 VectorCopy(r_shadow_selectedlight->angles, angles);
3793 VectorCopy(r_shadow_selectedlight->color, color);
3794 radius = r_shadow_selectedlight->radius;
3795 style = r_shadow_selectedlight->style;
3796 if (r_shadow_selectedlight->cubemapname)
3797 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3800 shadows = r_shadow_selectedlight->shadow;
3801 corona = r_shadow_selectedlight->corona;
3802 coronasizescale = r_shadow_selectedlight->coronasizescale;
3803 ambientscale = r_shadow_selectedlight->ambientscale;
3804 diffusescale = r_shadow_selectedlight->diffusescale;
3805 specularscale = r_shadow_selectedlight->specularscale;
3806 flags = r_shadow_selectedlight->flags;
3807 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3808 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3809 if (!strcmp(Cmd_Argv(1), "origin"))
3811 if (Cmd_Argc() != 5)
3813 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3816 origin[0] = atof(Cmd_Argv(2));
3817 origin[1] = atof(Cmd_Argv(3));
3818 origin[2] = atof(Cmd_Argv(4));
3820 else if (!strcmp(Cmd_Argv(1), "originx"))
3822 if (Cmd_Argc() != 3)
3824 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3827 origin[0] = atof(Cmd_Argv(2));
3829 else if (!strcmp(Cmd_Argv(1), "originy"))
3831 if (Cmd_Argc() != 3)
3833 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3836 origin[1] = atof(Cmd_Argv(2));
3838 else if (!strcmp(Cmd_Argv(1), "originz"))
3840 if (Cmd_Argc() != 3)
3842 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3845 origin[2] = atof(Cmd_Argv(2));
3847 else if (!strcmp(Cmd_Argv(1), "move"))
3849 if (Cmd_Argc() != 5)
3851 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3854 origin[0] += atof(Cmd_Argv(2));
3855 origin[1] += atof(Cmd_Argv(3));
3856 origin[2] += atof(Cmd_Argv(4));
3858 else if (!strcmp(Cmd_Argv(1), "movex"))
3860 if (Cmd_Argc() != 3)
3862 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3865 origin[0] += atof(Cmd_Argv(2));
3867 else if (!strcmp(Cmd_Argv(1), "movey"))
3869 if (Cmd_Argc() != 3)
3871 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3874 origin[1] += atof(Cmd_Argv(2));
3876 else if (!strcmp(Cmd_Argv(1), "movez"))
3878 if (Cmd_Argc() != 3)
3880 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3883 origin[2] += atof(Cmd_Argv(2));
3885 else if (!strcmp(Cmd_Argv(1), "angles"))
3887 if (Cmd_Argc() != 5)
3889 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3892 angles[0] = atof(Cmd_Argv(2));
3893 angles[1] = atof(Cmd_Argv(3));
3894 angles[2] = atof(Cmd_Argv(4));
3896 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3898 if (Cmd_Argc() != 3)
3900 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3903 angles[0] = atof(Cmd_Argv(2));
3905 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3907 if (Cmd_Argc() != 3)
3909 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3912 angles[1] = atof(Cmd_Argv(2));
3914 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3916 if (Cmd_Argc() != 3)
3918 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3921 angles[2] = atof(Cmd_Argv(2));
3923 else if (!strcmp(Cmd_Argv(1), "color"))
3925 if (Cmd_Argc() != 5)
3927 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3930 color[0] = atof(Cmd_Argv(2));
3931 color[1] = atof(Cmd_Argv(3));
3932 color[2] = atof(Cmd_Argv(4));
3934 else if (!strcmp(Cmd_Argv(1), "radius"))
3936 if (Cmd_Argc() != 3)
3938 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3941 radius = atof(Cmd_Argv(2));
3943 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3945 if (Cmd_Argc() == 3)
3947 double scale = atof(Cmd_Argv(2));
3954 if (Cmd_Argc() != 5)
3956 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of 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));
3964 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3966 if (Cmd_Argc() != 3)
3968 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3971 radius *= atof(Cmd_Argv(2));
3973 else if (!strcmp(Cmd_Argv(1), "style"))
3975 if (Cmd_Argc() != 3)
3977 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3980 style = atoi(Cmd_Argv(2));
3982 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3986 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3989 if (Cmd_Argc() == 3)
3990 strcpy(cubemapname, Cmd_Argv(2));
3994 else if (!strcmp(Cmd_Argv(1), "shadows"))
3996 if (Cmd_Argc() != 3)
3998 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4001 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4003 else if (!strcmp(Cmd_Argv(1), "corona"))
4005 if (Cmd_Argc() != 3)
4007 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4010 corona = atof(Cmd_Argv(2));
4012 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4014 if (Cmd_Argc() != 3)
4016 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4019 coronasizescale = atof(Cmd_Argv(2));
4021 else if (!strcmp(Cmd_Argv(1), "ambient"))
4023 if (Cmd_Argc() != 3)
4025 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4028 ambientscale = atof(Cmd_Argv(2));
4030 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4032 if (Cmd_Argc() != 3)
4034 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4037 diffusescale = atof(Cmd_Argv(2));
4039 else if (!strcmp(Cmd_Argv(1), "specular"))
4041 if (Cmd_Argc() != 3)
4043 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4046 specularscale = atof(Cmd_Argv(2));
4048 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4050 if (Cmd_Argc() != 3)
4052 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4055 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4057 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4059 if (Cmd_Argc() != 3)
4061 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4064 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4068 Con_Print("usage: r_editlights_edit [property] [value]\n");
4069 Con_Print("Selected light's properties:\n");
4070 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4071 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4072 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4073 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4074 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4075 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4076 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4077 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4078 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4079 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4080 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4081 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4082 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4083 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4086 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4087 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4090 void R_Shadow_EditLights_EditAll_f(void)
4094 if (!r_editlights.integer)
4096 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4100 for (light = r_shadow_worldlightchain;light;light = light->next)
4102 R_Shadow_SelectLight(light);
4103 R_Shadow_EditLights_Edit_f();
4107 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4109 int lightnumber, lightcount;
4113 if (!r_editlights.integer)
4119 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4120 if (light == r_shadow_selectedlight)
4121 lightnumber = lightcount;
4122 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;
4123 if (r_shadow_selectedlight == NULL)
4125 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4126 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;
4127 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;
4128 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;
4129 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4130 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4131 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4132 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;
4133 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4134 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4135 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4136 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4137 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4138 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;
4139 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;
4142 void R_Shadow_EditLights_ToggleShadow_f(void)
4144 if (!r_editlights.integer)
4146 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4149 if (!r_shadow_selectedlight)
4151 Con_Print("No selected light.\n");
4154 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);
4157 void R_Shadow_EditLights_ToggleCorona_f(void)
4159 if (!r_editlights.integer)
4161 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4164 if (!r_shadow_selectedlight)
4166 Con_Print("No selected light.\n");
4169 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);
4172 void R_Shadow_EditLights_Remove_f(void)
4174 if (!r_editlights.integer)
4176 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4179 if (!r_shadow_selectedlight)
4181 Con_Print("No selected light.\n");
4184 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4185 r_shadow_selectedlight = NULL;
4188 void R_Shadow_EditLights_Help_f(void)
4191 "Documentation on r_editlights system:\n"
4193 "r_editlights : enable/disable editing mode\n"
4194 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4195 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4196 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4197 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4198 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4200 "r_editlights_help : this help\n"
4201 "r_editlights_clear : remove all lights\n"
4202 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4203 "r_editlights_save : save to .rtlights file\n"
4204 "r_editlights_spawn : create a light with default settings\n"
4205 "r_editlights_edit command : edit selected light - more documentation below\n"
4206 "r_editlights_remove : remove selected light\n"
4207 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4208 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4209 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4211 "origin x y z : set light location\n"
4212 "originx x: set x component of light location\n"
4213 "originy y: set y component of light location\n"
4214 "originz z: set z component of light location\n"
4215 "move x y z : adjust light location\n"
4216 "movex x: adjust x component of light location\n"
4217 "movey y: adjust y component of light location\n"
4218 "movez z: adjust z component of light location\n"
4219 "angles x y z : set light angles\n"
4220 "anglesx x: set x component of light angles\n"
4221 "anglesy y: set y component of light angles\n"
4222 "anglesz z: set z component of light angles\n"
4223 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4224 "radius radius : set radius (size) of light\n"
4225 "colorscale grey : multiply color of light (1 does nothing)\n"
4226 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4227 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4228 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4229 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4230 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4231 "shadows 1/0 : turn on/off shadows\n"
4232 "corona n : set corona intensity\n"
4233 "coronasize n : set corona size (0-1)\n"
4234 "ambient n : set ambient intensity (0-1)\n"
4235 "diffuse n : set diffuse intensity (0-1)\n"
4236 "specular n : set specular intensity (0-1)\n"
4237 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4238 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4239 "<nothing> : print light properties to console\n"
4243 void R_Shadow_EditLights_CopyInfo_f(void)
4245 if (!r_editlights.integer)
4247 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4250 if (!r_shadow_selectedlight)
4252 Con_Print("No selected light.\n");
4255 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4256 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4257 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4258 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4259 if (r_shadow_selectedlight->cubemapname)
4260 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4262 r_shadow_bufferlight.cubemapname[0] = 0;
4263 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4264 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4265 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4266 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4267 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4268 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4269 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4272 void R_Shadow_EditLights_PasteInfo_f(void)
4274 if (!r_editlights.integer)
4276 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4279 if (!r_shadow_selectedlight)
4281 Con_Print("No selected light.\n");
4284 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);
4287 void R_Shadow_EditLights_Init(void)
4289 Cvar_RegisterVariable(&r_editlights);
4290 Cvar_RegisterVariable(&r_editlights_cursordistance);
4291 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4292 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4293 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4294 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4295 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4296 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4297 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4298 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4299 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4300 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4301 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4302 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4303 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4304 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4305 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4306 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4307 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4308 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);