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])
1634 // GLSL shader path (GFFX5200, Radeon 9500)
1635 // TODO: add direct pants/shirt rendering
1636 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1637 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1638 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1639 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1642 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1644 // TODO: add direct pants/shirt rendering
1645 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1646 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1647 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1648 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1649 if (r_shadow_rtlight->ambientscale)
1651 colorscale = r_shadow_rtlight->ambientscale;
1652 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1655 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1658 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1661 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1666 VectorScale(lightcolorbase, colorscale, color2);
1667 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1670 if (r_shadow_rtlight->diffusescale)
1672 colorscale = r_shadow_rtlight->diffusescale;
1673 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1675 // 3/2 3D combine path (Geforce3, Radeon 8500)
1678 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1680 // 1/2/2 3D combine path (original Radeon)
1683 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1685 // 2/2 3D combine path (original Radeon)
1688 else if (r_textureunits.integer >= 4)
1690 // 4/2 2D combine path (Geforce3, Radeon 8500)
1695 // 2/2/2 2D combine path (any dot3 card)
1698 VectorScale(lightcolorbase, colorscale, color2);
1699 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1702 if (specularscale && glosstexture != r_texture_black)
1704 //if (gl_support_blendsquare)
1706 colorscale = specularscale;
1707 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1709 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1713 VectorScale(lightcolorbase, colorscale, color2);
1714 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1721 // TODO: add direct pants/shirt rendering
1722 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1723 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1724 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1725 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1726 if (r_shadow_rtlight->ambientscale)
1728 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
1729 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1732 if (r_shadow_rtlight->diffusescale)
1734 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
1735 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1741 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1742 memset(&m, 0, sizeof(m));
1743 m.pointer_vertex = vertex3f;
1745 GL_LockArrays(firstvertex, numvertices);
1746 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1747 GL_LockArrays(0, 0);
1751 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1753 // GLSL shader path (GFFX5200, Radeon 9500)
1754 // TODO: add direct pants/shirt rendering
1755 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1756 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1757 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1758 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1759 R_Mesh_VertexPointer(vertex3f);
1760 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1761 R_Mesh_TexCoordPointer(1, 3, svector3f);
1762 R_Mesh_TexCoordPointer(2, 3, tvector3f);
1763 R_Mesh_TexCoordPointer(3, 3, normal3f);
1764 R_Mesh_TexBind(0, R_GetTexture(bumptexture));
1765 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1766 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1767 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1769 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1771 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1772 GL_LockArrays(firstvertex, numvertices);
1773 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1775 c_rt_lighttris += numtriangles;
1776 GL_LockArrays(0, 0);
1778 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
1780 // TODO: add direct pants/shirt rendering
1781 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1782 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1783 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1784 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1785 if (r_shadow_rtlight->ambientscale)
1788 colorscale = r_shadow_rtlight->ambientscale;
1789 // colorscale accounts for how much we multiply the brightness
1792 // mult is how many times the final pass of the lighting will be
1793 // performed to get more brightness than otherwise possible.
1795 // Limit mult to 64 for sanity sake.
1796 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1798 // 3 3D combine path (Geforce3, Radeon 8500)
1799 memset(&m, 0, sizeof(m));
1800 m.pointer_vertex = vertex3f;
1801 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1803 m.pointer_texcoord3f[0] = vertex3f;
1804 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1806 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1807 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1809 m.tex[1] = R_GetTexture(basetexture);
1810 m.pointer_texcoord[1] = texcoord2f;
1811 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1813 m.pointer_texcoord3f[2] = vertex3f;
1814 m.texmatrix[2] = r_shadow_entitytolight;
1816 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1817 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1819 GL_BlendFunc(GL_ONE, GL_ONE);
1821 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1823 // 2 3D combine path (Geforce3, original Radeon)
1824 memset(&m, 0, sizeof(m));
1825 m.pointer_vertex = vertex3f;
1826 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1828 m.pointer_texcoord3f[0] = vertex3f;
1829 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1831 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1832 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1834 m.tex[1] = R_GetTexture(basetexture);
1835 m.pointer_texcoord[1] = texcoord2f;
1836 GL_BlendFunc(GL_ONE, GL_ONE);
1838 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1840 // 4 2D combine path (Geforce3, Radeon 8500)
1841 memset(&m, 0, sizeof(m));
1842 m.pointer_vertex = vertex3f;
1843 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1845 m.pointer_texcoord3f[0] = vertex3f;
1846 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1848 m.pointer_texcoord[0] = varray_texcoord2f[0];
1849 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1851 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1853 m.pointer_texcoord3f[1] = vertex3f;
1854 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1856 m.pointer_texcoord[1] = varray_texcoord2f[1];
1857 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1859 m.tex[2] = R_GetTexture(basetexture);
1860 m.pointer_texcoord[2] = texcoord2f;
1861 if (r_shadow_lightcubemap != r_texture_whitecube)
1863 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1865 m.pointer_texcoord3f[3] = vertex3f;
1866 m.texmatrix[3] = r_shadow_entitytolight;
1868 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1869 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1872 GL_BlendFunc(GL_ONE, GL_ONE);
1874 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1876 // 3 2D combine path (Geforce3, original Radeon)
1877 memset(&m, 0, sizeof(m));
1878 m.pointer_vertex = vertex3f;
1879 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1881 m.pointer_texcoord3f[0] = vertex3f;
1882 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1884 m.pointer_texcoord[0] = varray_texcoord2f[0];
1885 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1887 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1889 m.pointer_texcoord3f[1] = vertex3f;
1890 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1892 m.pointer_texcoord[1] = varray_texcoord2f[1];
1893 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1895 m.tex[2] = R_GetTexture(basetexture);
1896 m.pointer_texcoord[2] = texcoord2f;
1897 GL_BlendFunc(GL_ONE, GL_ONE);
1901 // 2/2/2 2D combine path (any dot3 card)
1902 memset(&m, 0, sizeof(m));
1903 m.pointer_vertex = vertex3f;
1904 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1906 m.pointer_texcoord3f[0] = vertex3f;
1907 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1909 m.pointer_texcoord[0] = varray_texcoord2f[0];
1910 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1912 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1914 m.pointer_texcoord3f[1] = vertex3f;
1915 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1917 m.pointer_texcoord[1] = varray_texcoord2f[1];
1918 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1921 GL_ColorMask(0,0,0,1);
1922 GL_BlendFunc(GL_ONE, GL_ZERO);
1923 GL_LockArrays(firstvertex, numvertices);
1924 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1925 GL_LockArrays(0, 0);
1927 c_rt_lighttris += numtriangles;
1929 memset(&m, 0, sizeof(m));
1930 m.pointer_vertex = vertex3f;
1931 m.tex[0] = R_GetTexture(basetexture);
1932 m.pointer_texcoord[0] = texcoord2f;
1933 if (r_shadow_lightcubemap != r_texture_whitecube)
1935 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1937 m.pointer_texcoord3f[1] = vertex3f;
1938 m.texmatrix[1] = r_shadow_entitytolight;
1940 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1941 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1944 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1946 // this final code is shared
1948 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1949 VectorScale(lightcolorbase, colorscale, color2);
1950 GL_LockArrays(firstvertex, numvertices);
1951 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1953 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1954 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1956 c_rt_lighttris += numtriangles;
1958 GL_LockArrays(0, 0);
1960 if (r_shadow_rtlight->diffusescale)
1963 colorscale = r_shadow_rtlight->diffusescale;
1964 // colorscale accounts for how much we multiply the brightness
1967 // mult is how many times the final pass of the lighting will be
1968 // performed to get more brightness than otherwise possible.
1970 // Limit mult to 64 for sanity sake.
1971 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1973 // 3/2 3D combine path (Geforce3, Radeon 8500)
1974 memset(&m, 0, sizeof(m));
1975 m.pointer_vertex = vertex3f;
1976 m.tex[0] = R_GetTexture(bumptexture);
1977 m.texcombinergb[0] = GL_REPLACE;
1978 m.pointer_texcoord[0] = texcoord2f;
1979 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1980 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1981 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1982 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
1983 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1985 m.pointer_texcoord3f[2] = vertex3f;
1986 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1988 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1989 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1992 GL_ColorMask(0,0,0,1);
1993 GL_BlendFunc(GL_ONE, GL_ZERO);
1994 GL_LockArrays(firstvertex, numvertices);
1995 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1996 GL_LockArrays(0, 0);
1998 c_rt_lighttris += numtriangles;
2000 memset(&m, 0, sizeof(m));
2001 m.pointer_vertex = vertex3f;
2002 m.tex[0] = R_GetTexture(basetexture);
2003 m.pointer_texcoord[0] = texcoord2f;
2004 if (r_shadow_lightcubemap != r_texture_whitecube)
2006 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2008 m.pointer_texcoord3f[1] = vertex3f;
2009 m.texmatrix[1] = r_shadow_entitytolight;
2011 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2012 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2015 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2017 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
2019 // 1/2/2 3D combine path (original Radeon)
2020 memset(&m, 0, sizeof(m));
2021 m.pointer_vertex = vertex3f;
2022 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2024 m.pointer_texcoord3f[0] = vertex3f;
2025 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2027 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2028 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2031 GL_ColorMask(0,0,0,1);
2032 GL_BlendFunc(GL_ONE, GL_ZERO);
2033 GL_LockArrays(firstvertex, numvertices);
2034 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2035 GL_LockArrays(0, 0);
2037 c_rt_lighttris += numtriangles;
2039 memset(&m, 0, sizeof(m));
2040 m.pointer_vertex = vertex3f;
2041 m.tex[0] = R_GetTexture(bumptexture);
2042 m.texcombinergb[0] = GL_REPLACE;
2043 m.pointer_texcoord[0] = texcoord2f;
2044 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2045 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2046 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2047 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);
2049 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2050 GL_LockArrays(firstvertex, numvertices);
2051 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2052 GL_LockArrays(0, 0);
2054 c_rt_lighttris += numtriangles;
2056 memset(&m, 0, sizeof(m));
2057 m.pointer_vertex = vertex3f;
2058 m.tex[0] = R_GetTexture(basetexture);
2059 m.pointer_texcoord[0] = texcoord2f;
2060 if (r_shadow_lightcubemap != r_texture_whitecube)
2062 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2064 m.pointer_texcoord3f[1] = vertex3f;
2065 m.texmatrix[1] = r_shadow_entitytolight;
2067 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2068 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2071 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2073 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2075 // 2/2 3D combine path (original Radeon)
2076 memset(&m, 0, sizeof(m));
2077 m.pointer_vertex = vertex3f;
2078 m.tex[0] = R_GetTexture(bumptexture);
2079 m.texcombinergb[0] = GL_REPLACE;
2080 m.pointer_texcoord[0] = texcoord2f;
2081 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2082 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2083 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2084 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);
2086 GL_ColorMask(0,0,0,1);
2087 GL_BlendFunc(GL_ONE, GL_ZERO);
2088 GL_LockArrays(firstvertex, numvertices);
2089 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2090 GL_LockArrays(0, 0);
2092 c_rt_lighttris += numtriangles;
2094 memset(&m, 0, sizeof(m));
2095 m.pointer_vertex = vertex3f;
2096 m.tex[0] = R_GetTexture(basetexture);
2097 m.pointer_texcoord[0] = texcoord2f;
2098 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2100 m.pointer_texcoord3f[1] = vertex3f;
2101 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2103 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2104 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2106 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2108 else if (r_textureunits.integer >= 4)
2110 // 4/2 2D combine path (Geforce3, Radeon 8500)
2111 memset(&m, 0, sizeof(m));
2112 m.pointer_vertex = vertex3f;
2113 m.tex[0] = R_GetTexture(bumptexture);
2114 m.texcombinergb[0] = GL_REPLACE;
2115 m.pointer_texcoord[0] = texcoord2f;
2116 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2117 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2118 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2119 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);
2120 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2122 m.pointer_texcoord3f[2] = vertex3f;
2123 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2125 m.pointer_texcoord[2] = varray_texcoord2f[2];
2126 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2128 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2130 m.pointer_texcoord3f[3] = vertex3f;
2131 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2133 m.pointer_texcoord[3] = varray_texcoord2f[3];
2134 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2137 GL_ColorMask(0,0,0,1);
2138 GL_BlendFunc(GL_ONE, GL_ZERO);
2139 GL_LockArrays(firstvertex, numvertices);
2140 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2141 GL_LockArrays(0, 0);
2143 c_rt_lighttris += numtriangles;
2145 memset(&m, 0, sizeof(m));
2146 m.pointer_vertex = vertex3f;
2147 m.tex[0] = R_GetTexture(basetexture);
2148 m.pointer_texcoord[0] = texcoord2f;
2149 if (r_shadow_lightcubemap != r_texture_whitecube)
2151 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2153 m.pointer_texcoord3f[1] = vertex3f;
2154 m.texmatrix[1] = r_shadow_entitytolight;
2156 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2157 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2160 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2164 // 2/2/2 2D combine path (any dot3 card)
2165 memset(&m, 0, sizeof(m));
2166 m.pointer_vertex = vertex3f;
2167 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2169 m.pointer_texcoord3f[0] = vertex3f;
2170 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2172 m.pointer_texcoord[0] = varray_texcoord2f[0];
2173 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2175 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2177 m.pointer_texcoord3f[1] = vertex3f;
2178 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2180 m.pointer_texcoord[1] = varray_texcoord2f[1];
2181 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2184 GL_ColorMask(0,0,0,1);
2185 GL_BlendFunc(GL_ONE, GL_ZERO);
2186 GL_LockArrays(firstvertex, numvertices);
2187 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2188 GL_LockArrays(0, 0);
2190 c_rt_lighttris += numtriangles;
2192 memset(&m, 0, sizeof(m));
2193 m.pointer_vertex = vertex3f;
2194 m.tex[0] = R_GetTexture(bumptexture);
2195 m.texcombinergb[0] = GL_REPLACE;
2196 m.pointer_texcoord[0] = texcoord2f;
2197 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2198 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2199 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2200 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);
2202 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2203 GL_LockArrays(firstvertex, numvertices);
2204 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2205 GL_LockArrays(0, 0);
2207 c_rt_lighttris += numtriangles;
2209 memset(&m, 0, sizeof(m));
2210 m.pointer_vertex = vertex3f;
2211 m.tex[0] = R_GetTexture(basetexture);
2212 m.pointer_texcoord[0] = texcoord2f;
2213 if (r_shadow_lightcubemap != r_texture_whitecube)
2215 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2217 m.pointer_texcoord3f[1] = vertex3f;
2218 m.texmatrix[1] = r_shadow_entitytolight;
2220 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2221 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2224 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2226 // this final code is shared
2228 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2229 VectorScale(lightcolorbase, colorscale, color2);
2230 GL_LockArrays(firstvertex, numvertices);
2231 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2233 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2234 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2236 c_rt_lighttris += numtriangles;
2238 GL_LockArrays(0, 0);
2240 if (specularscale && glosstexture != r_texture_black)
2242 // FIXME: detect blendsquare!
2243 //if (gl_support_blendsquare)
2245 colorscale = specularscale;
2247 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2249 // 2/0/0/1/2 3D combine blendsquare path
2250 memset(&m, 0, sizeof(m));
2251 m.pointer_vertex = vertex3f;
2252 m.tex[0] = R_GetTexture(bumptexture);
2253 m.pointer_texcoord[0] = texcoord2f;
2254 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2255 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2256 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2257 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);
2259 GL_ColorMask(0,0,0,1);
2260 // this squares the result
2261 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2262 GL_LockArrays(firstvertex, numvertices);
2263 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2264 GL_LockArrays(0, 0);
2266 c_rt_lighttris += numtriangles;
2268 memset(&m, 0, sizeof(m));
2269 m.pointer_vertex = vertex3f;
2271 GL_LockArrays(firstvertex, numvertices);
2272 // square alpha in framebuffer a few times to make it shiny
2273 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2274 // these comments are a test run through this math for intensity 0.5
2275 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2276 // 0.25 * 0.25 = 0.0625 (this is another pass)
2277 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2278 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2280 c_rt_lighttris += numtriangles;
2281 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2283 c_rt_lighttris += numtriangles;
2284 GL_LockArrays(0, 0);
2286 memset(&m, 0, sizeof(m));
2287 m.pointer_vertex = vertex3f;
2288 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2290 m.pointer_texcoord3f[0] = vertex3f;
2291 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2293 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2294 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2297 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2298 GL_LockArrays(firstvertex, numvertices);
2299 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2300 GL_LockArrays(0, 0);
2302 c_rt_lighttris += numtriangles;
2304 memset(&m, 0, sizeof(m));
2305 m.pointer_vertex = vertex3f;
2306 m.tex[0] = R_GetTexture(glosstexture);
2307 m.pointer_texcoord[0] = texcoord2f;
2308 if (r_shadow_lightcubemap != r_texture_whitecube)
2310 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2312 m.pointer_texcoord3f[1] = vertex3f;
2313 m.texmatrix[1] = r_shadow_entitytolight;
2315 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2316 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2319 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2321 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2323 // 2/0/0/2 3D combine blendsquare path
2324 memset(&m, 0, sizeof(m));
2325 m.pointer_vertex = vertex3f;
2326 m.tex[0] = R_GetTexture(bumptexture);
2327 m.pointer_texcoord[0] = texcoord2f;
2328 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2329 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2330 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2331 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);
2333 GL_ColorMask(0,0,0,1);
2334 // this squares the result
2335 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2336 GL_LockArrays(firstvertex, numvertices);
2337 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2338 GL_LockArrays(0, 0);
2340 c_rt_lighttris += numtriangles;
2342 memset(&m, 0, sizeof(m));
2343 m.pointer_vertex = vertex3f;
2345 GL_LockArrays(firstvertex, numvertices);
2346 // square alpha in framebuffer a few times to make it shiny
2347 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2348 // these comments are a test run through this math for intensity 0.5
2349 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2350 // 0.25 * 0.25 = 0.0625 (this is another pass)
2351 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2352 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2354 c_rt_lighttris += numtriangles;
2355 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2357 c_rt_lighttris += numtriangles;
2358 GL_LockArrays(0, 0);
2360 memset(&m, 0, sizeof(m));
2361 m.pointer_vertex = vertex3f;
2362 m.tex[0] = R_GetTexture(glosstexture);
2363 m.pointer_texcoord[0] = texcoord2f;
2364 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2366 m.pointer_texcoord3f[1] = vertex3f;
2367 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2369 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2370 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2372 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2376 // 2/0/0/2/2 2D combine blendsquare path
2377 memset(&m, 0, sizeof(m));
2378 m.pointer_vertex = vertex3f;
2379 m.tex[0] = R_GetTexture(bumptexture);
2380 m.pointer_texcoord[0] = texcoord2f;
2381 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2382 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2383 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2384 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);
2386 GL_ColorMask(0,0,0,1);
2387 // this squares the result
2388 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2389 GL_LockArrays(firstvertex, numvertices);
2390 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2391 GL_LockArrays(0, 0);
2393 c_rt_lighttris += numtriangles;
2395 memset(&m, 0, sizeof(m));
2396 m.pointer_vertex = vertex3f;
2398 GL_LockArrays(firstvertex, numvertices);
2399 // square alpha in framebuffer a few times to make it shiny
2400 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2401 // these comments are a test run through this math for intensity 0.5
2402 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2403 // 0.25 * 0.25 = 0.0625 (this is another pass)
2404 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2405 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2407 c_rt_lighttris += numtriangles;
2408 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2410 c_rt_lighttris += numtriangles;
2411 GL_LockArrays(0, 0);
2413 memset(&m, 0, sizeof(m));
2414 m.pointer_vertex = vertex3f;
2415 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2417 m.pointer_texcoord3f[0] = vertex3f;
2418 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2420 m.pointer_texcoord[0] = varray_texcoord2f[0];
2421 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2423 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2425 m.pointer_texcoord3f[1] = vertex3f;
2426 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2428 m.pointer_texcoord[1] = varray_texcoord2f[1];
2429 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2432 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2433 GL_LockArrays(firstvertex, numvertices);
2434 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2435 GL_LockArrays(0, 0);
2437 c_rt_lighttris += numtriangles;
2439 memset(&m, 0, sizeof(m));
2440 m.pointer_vertex = vertex3f;
2441 m.tex[0] = R_GetTexture(glosstexture);
2442 m.pointer_texcoord[0] = texcoord2f;
2443 if (r_shadow_lightcubemap != r_texture_whitecube)
2445 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2447 m.pointer_texcoord3f[1] = vertex3f;
2448 m.texmatrix[1] = r_shadow_entitytolight;
2450 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2451 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2454 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2457 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2458 VectorScale(lightcolorbase, colorscale, color2);
2459 GL_LockArrays(firstvertex, numvertices);
2460 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2462 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2463 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2465 c_rt_lighttris += numtriangles;
2467 GL_LockArrays(0, 0);
2471 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
2473 // TODO: add direct pants/shirt rendering
2474 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2475 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
2476 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2477 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
2478 if (r_shadow_rtlight->ambientscale)
2480 GL_BlendFunc(GL_ONE, GL_ONE);
2481 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
2482 memset(&m, 0, sizeof(m));
2483 m.pointer_vertex = vertex3f;
2484 m.tex[0] = R_GetTexture(basetexture);
2485 m.pointer_texcoord[0] = texcoord2f;
2486 if (r_textureunits.integer >= 2)
2489 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2491 m.pointer_texcoord3f[1] = vertex3f;
2492 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2494 m.pointer_texcoord[1] = varray_texcoord2f[1];
2495 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2497 if (r_textureunits.integer >= 3)
2499 // Geforce3/Radeon class but not using dot3
2500 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2502 m.pointer_texcoord3f[2] = vertex3f;
2503 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2505 m.pointer_texcoord[2] = varray_texcoord2f[2];
2506 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2510 if (r_textureunits.integer >= 3)
2511 m.pointer_color = NULL;
2513 m.pointer_color = varray_color4f;
2515 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2517 color[0] = bound(0, color2[0], 1);
2518 color[1] = bound(0, color2[1], 1);
2519 color[2] = bound(0, color2[2], 1);
2520 if (r_textureunits.integer >= 3)
2521 GL_Color(color[0], color[1], color[2], 1);
2522 else if (r_textureunits.integer >= 2)
2523 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2525 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2526 GL_LockArrays(firstvertex, numvertices);
2527 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2528 GL_LockArrays(0, 0);
2530 c_rt_lighttris += numtriangles;
2533 if (r_shadow_rtlight->diffusescale)
2535 GL_BlendFunc(GL_ONE, GL_ONE);
2536 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
2537 memset(&m, 0, sizeof(m));
2538 m.pointer_vertex = vertex3f;
2539 m.pointer_color = varray_color4f;
2540 m.tex[0] = R_GetTexture(basetexture);
2541 m.pointer_texcoord[0] = texcoord2f;
2542 if (r_textureunits.integer >= 2)
2545 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2547 m.pointer_texcoord3f[1] = vertex3f;
2548 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2550 m.pointer_texcoord[1] = varray_texcoord2f[1];
2551 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2553 if (r_textureunits.integer >= 3)
2555 // Geforce3/Radeon class but not using dot3
2556 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2558 m.pointer_texcoord3f[2] = vertex3f;
2559 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2561 m.pointer_texcoord[2] = varray_texcoord2f[2];
2562 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2567 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2569 color[0] = bound(0, color2[0], 1);
2570 color[1] = bound(0, color2[1], 1);
2571 color[2] = bound(0, color2[2], 1);
2572 if (r_textureunits.integer >= 3)
2573 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2574 else if (r_textureunits.integer >= 2)
2575 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2577 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2578 GL_LockArrays(firstvertex, numvertices);
2579 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2580 GL_LockArrays(0, 0);
2582 c_rt_lighttris += numtriangles;
2588 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2592 R_RTLight_Uncompile(rtlight);
2593 memset(rtlight, 0, sizeof(*rtlight));
2595 VectorCopy(light->origin, rtlight->shadoworigin);
2596 VectorCopy(light->color, rtlight->color);
2597 rtlight->radius = light->radius;
2598 //rtlight->cullradius = rtlight->radius;
2599 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2600 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2601 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2602 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2603 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2604 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2605 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2606 rtlight->cubemapname[0] = 0;
2607 if (light->cubemapname[0])
2608 strcpy(rtlight->cubemapname, light->cubemapname);
2609 else if (light->cubemapnum > 0)
2610 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2611 rtlight->shadow = light->shadow;
2612 rtlight->corona = light->corona;
2613 rtlight->style = light->style;
2614 rtlight->isstatic = isstatic;
2615 rtlight->coronasizescale = light->coronasizescale;
2616 rtlight->ambientscale = light->ambientscale;
2617 rtlight->diffusescale = light->diffusescale;
2618 rtlight->specularscale = light->specularscale;
2619 rtlight->flags = light->flags;
2620 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2621 // ConcatScale won't work here because this needs to scale rotate and
2622 // translate, not just rotate
2623 scale = 1.0f / rtlight->radius;
2624 for (k = 0;k < 3;k++)
2625 for (j = 0;j < 4;j++)
2626 rtlight->matrix_worldtolight.m[k][j] *= scale;
2628 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2629 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2630 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2631 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2634 // compiles rtlight geometry
2635 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2636 void R_RTLight_Compile(rtlight_t *rtlight)
2638 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2639 entity_render_t *ent = r_refdef.worldentity;
2640 model_t *model = r_refdef.worldmodel;
2643 // compile the light
2644 rtlight->compiled = true;
2645 rtlight->static_numleafs = 0;
2646 rtlight->static_numleafpvsbytes = 0;
2647 rtlight->static_leaflist = NULL;
2648 rtlight->static_leafpvs = NULL;
2649 rtlight->static_numsurfaces = 0;
2650 rtlight->static_surfacelist = NULL;
2651 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2652 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2653 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2654 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2655 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2656 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2658 if (model && model->GetLightInfo)
2660 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2661 r_shadow_compilingrtlight = rtlight;
2662 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2663 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);
2664 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2665 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2666 rtlight->static_numleafs = numleafs;
2667 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2668 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2669 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2670 rtlight->static_numsurfaces = numsurfaces;
2671 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2673 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2674 if (numleafpvsbytes)
2675 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2677 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2678 if (model->DrawShadowVolume && rtlight->shadow)
2680 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2681 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2682 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2684 if (model->DrawLight)
2686 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2687 model->DrawLight(ent, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
2688 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2690 // switch back to rendering when DrawShadowVolume or DrawLight is called
2691 r_shadow_compilingrtlight = NULL;
2695 // use smallest available cullradius - box radius or light radius
2696 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2697 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2701 if (rtlight->static_meshchain_shadow)
2704 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2707 shadowtris += mesh->numtriangles;
2713 if (rtlight->static_meshchain_light)
2716 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2719 lighttris += mesh->numtriangles;
2723 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);
2726 void R_RTLight_Uncompile(rtlight_t *rtlight)
2728 if (rtlight->compiled)
2730 if (rtlight->static_meshchain_shadow)
2731 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2732 rtlight->static_meshchain_shadow = NULL;
2733 if (rtlight->static_meshchain_light)
2734 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2735 rtlight->static_meshchain_light = NULL;
2736 // these allocations are grouped
2737 if (rtlight->static_leaflist)
2738 Mem_Free(rtlight->static_leaflist);
2739 rtlight->static_numleafs = 0;
2740 rtlight->static_numleafpvsbytes = 0;
2741 rtlight->static_leaflist = NULL;
2742 rtlight->static_leafpvs = NULL;
2743 rtlight->static_numsurfaces = 0;
2744 rtlight->static_surfacelist = NULL;
2745 rtlight->compiled = false;
2749 void R_Shadow_UncompileWorldLights(void)
2752 for (light = r_shadow_worldlightchain;light;light = light->next)
2753 R_RTLight_Uncompile(&light->rtlight);
2756 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2758 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2759 vec_t relativeshadowradius;
2760 if (ent == r_refdef.worldentity)
2762 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2765 R_Mesh_Matrix(&ent->matrix);
2766 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2768 R_Mesh_VertexPointer(mesh->vertex3f);
2769 GL_LockArrays(0, mesh->numverts);
2770 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2772 // decrement stencil if backface is behind depthbuffer
2773 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2774 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2775 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2776 c_rtcached_shadowmeshes++;
2777 c_rtcached_shadowtris += mesh->numtriangles;
2778 // increment stencil if frontface is behind depthbuffer
2779 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2780 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2782 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2783 c_rtcached_shadowmeshes++;
2784 c_rtcached_shadowtris += mesh->numtriangles;
2785 GL_LockArrays(0, 0);
2788 else if (numsurfaces)
2790 R_Mesh_Matrix(&ent->matrix);
2791 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2796 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2797 relativeshadowradius = rtlight->radius / ent->scale;
2798 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2799 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2800 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2801 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2802 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2803 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2804 R_Mesh_Matrix(&ent->matrix);
2805 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2809 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2812 // set up properties for rendering light onto this entity
2813 r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2814 r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2815 r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2816 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2817 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2818 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2819 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2820 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2821 R_Mesh_Matrix(&ent->matrix);
2822 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2824 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2825 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2826 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2827 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2829 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2832 if (ent == r_refdef.worldentity)
2834 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2836 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2837 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);
2840 ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2843 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2846 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2851 int numleafs, numsurfaces;
2852 int *leaflist, *surfacelist;
2854 int numlightentities;
2855 int numshadowentities;
2856 entity_render_t *lightentities[MAX_EDICTS];
2857 entity_render_t *shadowentities[MAX_EDICTS];
2859 // skip lights that don't light (corona only lights)
2860 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2863 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2864 VectorScale(rtlight->color, f, lightcolor);
2865 if (VectorLength2(lightcolor) < 0.01)
2868 if (rtlight->selected)
2870 f = 2 + sin(realtime * M_PI * 4.0);
2871 VectorScale(lightcolor, f, lightcolor);
2875 // loading is done before visibility checks because loading should happen
2876 // all at once at the start of a level, not when it stalls gameplay.
2877 // (especially important to benchmarks)
2879 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2880 R_RTLight_Compile(rtlight);
2882 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2884 // if the light box is offscreen, skip it
2885 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2888 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2890 // compiled light, world available and can receive realtime lighting
2891 // retrieve leaf information
2892 numleafs = rtlight->static_numleafs;
2893 leaflist = rtlight->static_leaflist;
2894 leafpvs = rtlight->static_leafpvs;
2895 numsurfaces = rtlight->static_numsurfaces;
2896 surfacelist = rtlight->static_surfacelist;
2898 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2900 // dynamic light, world available and can receive realtime lighting
2901 // calculate lit surfaces and leafs
2902 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2903 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);
2904 leaflist = r_shadow_buffer_leaflist;
2905 leafpvs = r_shadow_buffer_leafpvs;
2906 surfacelist = r_shadow_buffer_surfacelist;
2907 // if the reduced leaf bounds are offscreen, skip it
2908 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2920 // check if light is illuminating any visible leafs
2923 for (i = 0;i < numleafs;i++)
2924 if (r_worldleafvisible[leaflist[i]])
2929 // set up a scissor rectangle for this light
2930 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2933 numlightentities = 0;
2935 lightentities[numlightentities++] = r_refdef.worldentity;
2936 numshadowentities = 0;
2938 shadowentities[numshadowentities++] = r_refdef.worldentity;
2939 if (r_drawentities.integer)
2941 for (i = 0;i < r_refdef.numentities;i++)
2943 entity_render_t *ent = r_refdef.entities[i];
2944 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2946 && !(ent->flags & RENDER_TRANSPARENT)
2947 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2949 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2950 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2951 shadowentities[numshadowentities++] = ent;
2952 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2953 lightentities[numlightentities++] = ent;
2958 // return if there's nothing at all to light
2959 if (!numlightentities)
2962 R_Shadow_Stage_ActiveLight(rtlight);
2966 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2969 R_Shadow_Stage_StencilShadowVolumes();
2970 for (i = 0;i < numshadowentities;i++)
2971 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2974 if (numlightentities && !visible)
2976 R_Shadow_Stage_Lighting(usestencil);
2977 for (i = 0;i < numlightentities;i++)
2978 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2981 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2983 R_Shadow_Stage_VisibleShadowVolumes();
2984 for (i = 0;i < numshadowentities;i++)
2985 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2988 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2990 R_Shadow_Stage_VisibleLighting(usestencil);
2991 for (i = 0;i < numlightentities;i++)
2992 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2996 void R_ShadowVolumeLighting(qboolean visible)
3001 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3002 R_Shadow_EditLights_Reload_f();
3004 R_Shadow_Stage_Begin();
3006 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3007 if (r_shadow_debuglight.integer >= 0)
3009 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3010 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3011 R_DrawRTLight(&light->rtlight, visible);
3014 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3015 if (light->flags & flag)
3016 R_DrawRTLight(&light->rtlight, visible);
3018 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
3019 R_DrawRTLight(&light->rtlight, visible);
3021 R_Shadow_Stage_End();
3024 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3025 typedef struct suffixinfo_s
3028 qboolean flipx, flipy, flipdiagonal;
3031 static suffixinfo_t suffix[3][6] =
3034 {"px", false, false, false},
3035 {"nx", false, false, false},
3036 {"py", false, false, false},
3037 {"ny", false, false, false},
3038 {"pz", false, false, false},
3039 {"nz", false, false, false}
3042 {"posx", false, false, false},
3043 {"negx", false, false, false},
3044 {"posy", false, false, false},
3045 {"negy", false, false, false},
3046 {"posz", false, false, false},
3047 {"negz", false, false, false}
3050 {"rt", true, false, true},
3051 {"lf", false, true, true},
3052 {"ft", true, true, false},
3053 {"bk", false, false, false},
3054 {"up", true, false, true},
3055 {"dn", true, false, true}
3059 static int componentorder[4] = {0, 1, 2, 3};
3061 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3063 int i, j, cubemapsize;
3064 qbyte *cubemappixels, *image_rgba;
3065 rtexture_t *cubemaptexture;
3067 // must start 0 so the first loadimagepixels has no requested width/height
3069 cubemappixels = NULL;
3070 cubemaptexture = NULL;
3071 // keep trying different suffix groups (posx, px, rt) until one loads
3072 for (j = 0;j < 3 && !cubemappixels;j++)
3074 // load the 6 images in the suffix group
3075 for (i = 0;i < 6;i++)
3077 // generate an image name based on the base and and suffix
3078 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3080 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3082 // an image loaded, make sure width and height are equal
3083 if (image_width == image_height)
3085 // if this is the first image to load successfully, allocate the cubemap memory
3086 if (!cubemappixels && image_width >= 1)
3088 cubemapsize = image_width;
3089 // note this clears to black, so unavailable sides are black
3090 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3092 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3094 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);
3097 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3099 Mem_Free(image_rgba);
3103 // if a cubemap loaded, upload it
3106 if (!r_shadow_filters_texturepool)
3107 r_shadow_filters_texturepool = R_AllocTexturePool();
3108 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3109 Mem_Free(cubemappixels);
3113 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3114 for (j = 0;j < 3;j++)
3115 for (i = 0;i < 6;i++)
3116 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3117 Con_Print(" and was unable to find any of them.\n");
3119 return cubemaptexture;
3122 rtexture_t *R_Shadow_Cubemap(const char *basename)
3125 for (i = 0;i < numcubemaps;i++)
3126 if (!strcasecmp(cubemaps[i].basename, basename))
3127 return cubemaps[i].texture;
3128 if (i >= MAX_CUBEMAPS)
3129 return r_texture_whitecube;
3131 strcpy(cubemaps[i].basename, basename);
3132 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3133 if (!cubemaps[i].texture)
3134 cubemaps[i].texture = r_texture_whitecube;
3135 return cubemaps[i].texture;
3138 void R_Shadow_FreeCubemaps(void)
3141 R_FreeTexturePool(&r_shadow_filters_texturepool);
3144 dlight_t *R_Shadow_NewWorldLight(void)
3147 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3148 light->next = r_shadow_worldlightchain;
3149 r_shadow_worldlightchain = light;
3153 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)
3155 VectorCopy(origin, light->origin);
3156 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3157 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3158 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3159 light->color[0] = max(color[0], 0);
3160 light->color[1] = max(color[1], 0);
3161 light->color[2] = max(color[2], 0);
3162 light->radius = max(radius, 0);
3163 light->style = style;
3164 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3166 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3169 light->shadow = shadowenable;
3170 light->corona = corona;
3173 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3174 light->coronasizescale = coronasizescale;
3175 light->ambientscale = ambientscale;
3176 light->diffusescale = diffusescale;
3177 light->specularscale = specularscale;
3178 light->flags = flags;
3179 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3181 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3184 void R_Shadow_FreeWorldLight(dlight_t *light)
3186 dlight_t **lightpointer;
3187 R_RTLight_Uncompile(&light->rtlight);
3188 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3189 if (*lightpointer != light)
3190 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3191 *lightpointer = light->next;
3195 void R_Shadow_ClearWorldLights(void)
3197 while (r_shadow_worldlightchain)
3198 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3199 r_shadow_selectedlight = NULL;
3200 R_Shadow_FreeCubemaps();
3203 void R_Shadow_SelectLight(dlight_t *light)
3205 if (r_shadow_selectedlight)
3206 r_shadow_selectedlight->selected = false;
3207 r_shadow_selectedlight = light;
3208 if (r_shadow_selectedlight)
3209 r_shadow_selectedlight->selected = true;
3212 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3214 float scale = r_editlights_cursorgrid.value * 0.5f;
3215 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);
3218 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3221 const dlight_t *light;
3224 if (light->selected)
3225 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3228 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);
3231 void R_Shadow_DrawLightSprites(void)
3237 for (i = 0;i < 5;i++)
3239 lighttextures[i] = NULL;
3240 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3241 lighttextures[i] = pic->tex;
3244 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3245 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3246 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3249 void R_Shadow_SelectLightInView(void)
3251 float bestrating, rating, temp[3];
3252 dlight_t *best, *light;
3255 for (light = r_shadow_worldlightchain;light;light = light->next)
3257 VectorSubtract(light->origin, r_vieworigin, temp);
3258 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3261 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3262 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3264 bestrating = rating;
3269 R_Shadow_SelectLight(best);
3272 void R_Shadow_LoadWorldLights(void)
3274 int n, a, style, shadow, flags;
3275 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3276 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3277 if (r_refdef.worldmodel == NULL)
3279 Con_Print("No map loaded.\n");
3282 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3283 strlcat (name, ".rtlights", sizeof (name));
3284 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3294 for (;COM_Parse(t, true) && strcmp(
3295 if (COM_Parse(t, true))
3297 if (com_token[0] == '!')
3300 origin[0] = atof(com_token+1);
3303 origin[0] = atof(com_token);
3308 while (*s && *s != '\n' && *s != '\r')
3314 // check for modifier flags
3321 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);
3324 flags = LIGHTFLAG_REALTIMEMODE;
3332 coronasizescale = 0.25f;
3334 VectorClear(angles);
3337 if (a < 9 || !strcmp(cubemapname, "\"\""))
3339 // remove quotes on cubemapname
3340 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3342 cubemapname[strlen(cubemapname)-1] = 0;
3343 strcpy(cubemapname, cubemapname + 1);
3347 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);
3350 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3358 Con_Printf("invalid rtlights file \"%s\"\n", name);
3359 Mem_Free(lightsstring);
3363 void R_Shadow_SaveWorldLights(void)
3366 size_t bufchars, bufmaxchars;
3368 char name[MAX_QPATH];
3370 if (!r_shadow_worldlightchain)
3372 if (r_refdef.worldmodel == NULL)
3374 Con_Print("No map loaded.\n");
3377 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3378 strlcat (name, ".rtlights", sizeof (name));
3379 bufchars = bufmaxchars = 0;
3381 for (light = r_shadow_worldlightchain;light;light = light->next)
3383 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3384 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);
3385 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3386 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]);
3388 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);
3389 if (bufchars + (int) strlen(line) > bufmaxchars)
3391 bufmaxchars = bufchars + strlen(line) + 2048;
3393 buf = Mem_Alloc(tempmempool, bufmaxchars);
3397 memcpy(buf, oldbuf, bufchars);
3403 memcpy(buf + bufchars, line, strlen(line));
3404 bufchars += strlen(line);
3408 FS_WriteFile(name, buf, bufchars);
3413 void R_Shadow_LoadLightsFile(void)
3416 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3417 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3418 if (r_refdef.worldmodel == NULL)
3420 Con_Print("No map loaded.\n");
3423 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3424 strlcat (name, ".lights", sizeof (name));
3425 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3433 while (*s && *s != '\n' && *s != '\r')
3439 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);
3443 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);
3446 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3447 radius = bound(15, radius, 4096);
3448 VectorScale(color, (2.0f / (8388608.0f)), color);
3449 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3457 Con_Printf("invalid lights file \"%s\"\n", name);
3458 Mem_Free(lightsstring);
3462 // tyrlite/hmap2 light types in the delay field
3463 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3465 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3467 int entnum, style, islight, skin, pflags, effects, type, n;
3470 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3471 char key[256], value[1024];
3473 if (r_refdef.worldmodel == NULL)
3475 Con_Print("No map loaded.\n");
3478 // try to load a .ent file first
3479 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3480 strlcat (key, ".ent", sizeof (key));
3481 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true);
3482 // and if that is not found, fall back to the bsp file entity string
3484 data = r_refdef.worldmodel->brush.entities;
3487 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3489 type = LIGHTTYPE_MINUSX;
3490 origin[0] = origin[1] = origin[2] = 0;
3491 originhack[0] = originhack[1] = originhack[2] = 0;
3492 angles[0] = angles[1] = angles[2] = 0;
3493 color[0] = color[1] = color[2] = 1;
3494 light[0] = light[1] = light[2] = 1;light[3] = 300;
3495 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3505 if (!COM_ParseToken(&data, false))
3507 if (com_token[0] == '}')
3508 break; // end of entity
3509 if (com_token[0] == '_')
3510 strcpy(key, com_token + 1);
3512 strcpy(key, com_token);
3513 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3514 key[strlen(key)-1] = 0;
3515 if (!COM_ParseToken(&data, false))
3517 strcpy(value, com_token);
3519 // now that we have the key pair worked out...
3520 if (!strcmp("light", key))
3522 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3526 light[0] = vec[0] * (1.0f / 256.0f);
3527 light[1] = vec[0] * (1.0f / 256.0f);
3528 light[2] = vec[0] * (1.0f / 256.0f);
3534 light[0] = vec[0] * (1.0f / 255.0f);
3535 light[1] = vec[1] * (1.0f / 255.0f);
3536 light[2] = vec[2] * (1.0f / 255.0f);
3540 else if (!strcmp("delay", key))
3542 else if (!strcmp("origin", key))
3543 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3544 else if (!strcmp("angle", key))
3545 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3546 else if (!strcmp("angles", key))
3547 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3548 else if (!strcmp("color", key))
3549 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3550 else if (!strcmp("wait", key))
3551 fadescale = atof(value);
3552 else if (!strcmp("classname", key))
3554 if (!strncmp(value, "light", 5))
3557 if (!strcmp(value, "light_fluoro"))
3562 overridecolor[0] = 1;
3563 overridecolor[1] = 1;
3564 overridecolor[2] = 1;
3566 if (!strcmp(value, "light_fluorospark"))
3571 overridecolor[0] = 1;
3572 overridecolor[1] = 1;
3573 overridecolor[2] = 1;
3575 if (!strcmp(value, "light_globe"))
3580 overridecolor[0] = 1;
3581 overridecolor[1] = 0.8;
3582 overridecolor[2] = 0.4;
3584 if (!strcmp(value, "light_flame_large_yellow"))
3589 overridecolor[0] = 1;
3590 overridecolor[1] = 0.5;
3591 overridecolor[2] = 0.1;
3593 if (!strcmp(value, "light_flame_small_yellow"))
3598 overridecolor[0] = 1;
3599 overridecolor[1] = 0.5;
3600 overridecolor[2] = 0.1;
3602 if (!strcmp(value, "light_torch_small_white"))
3607 overridecolor[0] = 1;
3608 overridecolor[1] = 0.5;
3609 overridecolor[2] = 0.1;
3611 if (!strcmp(value, "light_torch_small_walltorch"))
3616 overridecolor[0] = 1;
3617 overridecolor[1] = 0.5;
3618 overridecolor[2] = 0.1;
3622 else if (!strcmp("style", key))
3623 style = atoi(value);
3624 else if (r_refdef.worldmodel->type == mod_brushq3)
3626 if (!strcmp("scale", key))
3627 lightscale = atof(value);
3628 if (!strcmp("fade", key))
3629 fadescale = atof(value);
3631 else if (!strcmp("skin", key))
3632 skin = (int)atof(value);
3633 else if (!strcmp("pflags", key))
3634 pflags = (int)atof(value);
3635 else if (!strcmp("effects", key))
3636 effects = (int)atof(value);
3640 if (lightscale <= 0)
3644 if (color[0] == color[1] && color[0] == color[2])
3646 color[0] *= overridecolor[0];
3647 color[1] *= overridecolor[1];
3648 color[2] *= overridecolor[2];
3650 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3651 color[0] = color[0] * light[0];
3652 color[1] = color[1] * light[1];
3653 color[2] = color[2] * light[2];
3656 case LIGHTTYPE_MINUSX:
3658 case LIGHTTYPE_RECIPX:
3660 VectorScale(color, (1.0f / 16.0f), color);
3662 case LIGHTTYPE_RECIPXX:
3664 VectorScale(color, (1.0f / 16.0f), color);
3667 case LIGHTTYPE_NONE:
3671 case LIGHTTYPE_MINUSXX:
3674 VectorAdd(origin, originhack, origin);
3676 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);
3679 Mem_Free(entfiledata);
3683 void R_Shadow_SetCursorLocationForView(void)
3686 vec3_t dest, endpos;
3688 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3689 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3690 if (trace.fraction < 1)
3692 dist = trace.fraction * r_editlights_cursordistance.value;
3693 push = r_editlights_cursorpushback.value;
3697 VectorMA(trace.endpos, push, r_viewforward, endpos);
3698 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3700 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3701 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3702 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3705 void R_Shadow_UpdateWorldLightSelection(void)
3707 if (r_editlights.integer)
3709 R_Shadow_SetCursorLocationForView();
3710 R_Shadow_SelectLightInView();
3711 R_Shadow_DrawLightSprites();
3714 R_Shadow_SelectLight(NULL);
3717 void R_Shadow_EditLights_Clear_f(void)
3719 R_Shadow_ClearWorldLights();
3722 void R_Shadow_EditLights_Reload_f(void)
3724 if (!r_refdef.worldmodel)
3726 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3727 R_Shadow_ClearWorldLights();
3728 R_Shadow_LoadWorldLights();
3729 if (r_shadow_worldlightchain == NULL)
3731 R_Shadow_LoadLightsFile();
3732 if (r_shadow_worldlightchain == NULL)
3733 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3737 void R_Shadow_EditLights_Save_f(void)
3739 if (!r_refdef.worldmodel)
3741 R_Shadow_SaveWorldLights();
3744 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3746 R_Shadow_ClearWorldLights();
3747 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3750 void R_Shadow_EditLights_ImportLightsFile_f(void)
3752 R_Shadow_ClearWorldLights();
3753 R_Shadow_LoadLightsFile();
3756 void R_Shadow_EditLights_Spawn_f(void)
3759 if (!r_editlights.integer)
3761 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3764 if (Cmd_Argc() != 1)
3766 Con_Print("r_editlights_spawn does not take parameters\n");
3769 color[0] = color[1] = color[2] = 1;
3770 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3773 void R_Shadow_EditLights_Edit_f(void)
3775 vec3_t origin, angles, color;
3776 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3777 int style, shadows, flags, normalmode, realtimemode;
3778 char cubemapname[1024];
3779 if (!r_editlights.integer)
3781 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3784 if (!r_shadow_selectedlight)
3786 Con_Print("No selected light.\n");
3789 VectorCopy(r_shadow_selectedlight->origin, origin);
3790 VectorCopy(r_shadow_selectedlight->angles, angles);
3791 VectorCopy(r_shadow_selectedlight->color, color);
3792 radius = r_shadow_selectedlight->radius;
3793 style = r_shadow_selectedlight->style;
3794 if (r_shadow_selectedlight->cubemapname)
3795 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3798 shadows = r_shadow_selectedlight->shadow;
3799 corona = r_shadow_selectedlight->corona;
3800 coronasizescale = r_shadow_selectedlight->coronasizescale;
3801 ambientscale = r_shadow_selectedlight->ambientscale;
3802 diffusescale = r_shadow_selectedlight->diffusescale;
3803 specularscale = r_shadow_selectedlight->specularscale;
3804 flags = r_shadow_selectedlight->flags;
3805 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3806 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3807 if (!strcmp(Cmd_Argv(1), "origin"))
3809 if (Cmd_Argc() != 5)
3811 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3814 origin[0] = atof(Cmd_Argv(2));
3815 origin[1] = atof(Cmd_Argv(3));
3816 origin[2] = atof(Cmd_Argv(4));
3818 else if (!strcmp(Cmd_Argv(1), "originx"))
3820 if (Cmd_Argc() != 3)
3822 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3825 origin[0] = atof(Cmd_Argv(2));
3827 else if (!strcmp(Cmd_Argv(1), "originy"))
3829 if (Cmd_Argc() != 3)
3831 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3834 origin[1] = atof(Cmd_Argv(2));
3836 else if (!strcmp(Cmd_Argv(1), "originz"))
3838 if (Cmd_Argc() != 3)
3840 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3843 origin[2] = atof(Cmd_Argv(2));
3845 else if (!strcmp(Cmd_Argv(1), "move"))
3847 if (Cmd_Argc() != 5)
3849 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3852 origin[0] += atof(Cmd_Argv(2));
3853 origin[1] += atof(Cmd_Argv(3));
3854 origin[2] += atof(Cmd_Argv(4));
3856 else if (!strcmp(Cmd_Argv(1), "movex"))
3858 if (Cmd_Argc() != 3)
3860 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3863 origin[0] += atof(Cmd_Argv(2));
3865 else if (!strcmp(Cmd_Argv(1), "movey"))
3867 if (Cmd_Argc() != 3)
3869 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3872 origin[1] += atof(Cmd_Argv(2));
3874 else if (!strcmp(Cmd_Argv(1), "movez"))
3876 if (Cmd_Argc() != 3)
3878 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3881 origin[2] += atof(Cmd_Argv(2));
3883 else if (!strcmp(Cmd_Argv(1), "angles"))
3885 if (Cmd_Argc() != 5)
3887 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3890 angles[0] = atof(Cmd_Argv(2));
3891 angles[1] = atof(Cmd_Argv(3));
3892 angles[2] = atof(Cmd_Argv(4));
3894 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3896 if (Cmd_Argc() != 3)
3898 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3901 angles[0] = atof(Cmd_Argv(2));
3903 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3905 if (Cmd_Argc() != 3)
3907 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3910 angles[1] = atof(Cmd_Argv(2));
3912 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3914 if (Cmd_Argc() != 3)
3916 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3919 angles[2] = atof(Cmd_Argv(2));
3921 else if (!strcmp(Cmd_Argv(1), "color"))
3923 if (Cmd_Argc() != 5)
3925 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3928 color[0] = atof(Cmd_Argv(2));
3929 color[1] = atof(Cmd_Argv(3));
3930 color[2] = atof(Cmd_Argv(4));
3932 else if (!strcmp(Cmd_Argv(1), "radius"))
3934 if (Cmd_Argc() != 3)
3936 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3939 radius = atof(Cmd_Argv(2));
3941 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3943 if (Cmd_Argc() == 3)
3945 double scale = atof(Cmd_Argv(2));
3952 if (Cmd_Argc() != 5)
3954 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3957 color[0] *= atof(Cmd_Argv(2));
3958 color[1] *= atof(Cmd_Argv(3));
3959 color[2] *= atof(Cmd_Argv(4));
3962 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3964 if (Cmd_Argc() != 3)
3966 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3969 radius *= atof(Cmd_Argv(2));
3971 else if (!strcmp(Cmd_Argv(1), "style"))
3973 if (Cmd_Argc() != 3)
3975 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3978 style = atoi(Cmd_Argv(2));
3980 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3984 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3987 if (Cmd_Argc() == 3)
3988 strcpy(cubemapname, Cmd_Argv(2));
3992 else if (!strcmp(Cmd_Argv(1), "shadows"))
3994 if (Cmd_Argc() != 3)
3996 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3999 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4001 else if (!strcmp(Cmd_Argv(1), "corona"))
4003 if (Cmd_Argc() != 3)
4005 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4008 corona = atof(Cmd_Argv(2));
4010 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4012 if (Cmd_Argc() != 3)
4014 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4017 coronasizescale = atof(Cmd_Argv(2));
4019 else if (!strcmp(Cmd_Argv(1), "ambient"))
4021 if (Cmd_Argc() != 3)
4023 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4026 ambientscale = atof(Cmd_Argv(2));
4028 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4030 if (Cmd_Argc() != 3)
4032 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4035 diffusescale = atof(Cmd_Argv(2));
4037 else if (!strcmp(Cmd_Argv(1), "specular"))
4039 if (Cmd_Argc() != 3)
4041 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4044 specularscale = atof(Cmd_Argv(2));
4046 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4048 if (Cmd_Argc() != 3)
4050 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4053 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4055 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4057 if (Cmd_Argc() != 3)
4059 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4062 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4066 Con_Print("usage: r_editlights_edit [property] [value]\n");
4067 Con_Print("Selected light's properties:\n");
4068 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4069 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4070 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4071 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4072 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4073 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4074 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4075 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4076 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4077 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4078 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4079 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4080 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4081 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4084 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4085 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4088 void R_Shadow_EditLights_EditAll_f(void)
4092 if (!r_editlights.integer)
4094 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4098 for (light = r_shadow_worldlightchain;light;light = light->next)
4100 R_Shadow_SelectLight(light);
4101 R_Shadow_EditLights_Edit_f();
4105 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4107 int lightnumber, lightcount;
4111 if (!r_editlights.integer)
4117 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4118 if (light == r_shadow_selectedlight)
4119 lightnumber = lightcount;
4120 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;
4121 if (r_shadow_selectedlight == NULL)
4123 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4124 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;
4125 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;
4126 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;
4127 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4128 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4129 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4130 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;
4131 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4132 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4133 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4134 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4135 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4136 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;
4137 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;
4140 void R_Shadow_EditLights_ToggleShadow_f(void)
4142 if (!r_editlights.integer)
4144 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4147 if (!r_shadow_selectedlight)
4149 Con_Print("No selected light.\n");
4152 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);
4155 void R_Shadow_EditLights_ToggleCorona_f(void)
4157 if (!r_editlights.integer)
4159 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4162 if (!r_shadow_selectedlight)
4164 Con_Print("No selected light.\n");
4167 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);
4170 void R_Shadow_EditLights_Remove_f(void)
4172 if (!r_editlights.integer)
4174 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4177 if (!r_shadow_selectedlight)
4179 Con_Print("No selected light.\n");
4182 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4183 r_shadow_selectedlight = NULL;
4186 void R_Shadow_EditLights_Help_f(void)
4189 "Documentation on r_editlights system:\n"
4191 "r_editlights : enable/disable editing mode\n"
4192 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4193 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4194 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4195 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4196 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4198 "r_editlights_help : this help\n"
4199 "r_editlights_clear : remove all lights\n"
4200 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4201 "r_editlights_save : save to .rtlights file\n"
4202 "r_editlights_spawn : create a light with default settings\n"
4203 "r_editlights_edit command : edit selected light - more documentation below\n"
4204 "r_editlights_remove : remove selected light\n"
4205 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4206 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4207 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4209 "origin x y z : set light location\n"
4210 "originx x: set x component of light location\n"
4211 "originy y: set y component of light location\n"
4212 "originz z: set z component of light location\n"
4213 "move x y z : adjust light location\n"
4214 "movex x: adjust x component of light location\n"
4215 "movey y: adjust y component of light location\n"
4216 "movez z: adjust z component of light location\n"
4217 "angles x y z : set light angles\n"
4218 "anglesx x: set x component of light angles\n"
4219 "anglesy y: set y component of light angles\n"
4220 "anglesz z: set z component of light angles\n"
4221 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4222 "radius radius : set radius (size) of light\n"
4223 "colorscale grey : multiply color of light (1 does nothing)\n"
4224 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4225 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4226 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4227 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4228 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4229 "shadows 1/0 : turn on/off shadows\n"
4230 "corona n : set corona intensity\n"
4231 "coronasize n : set corona size (0-1)\n"
4232 "ambient n : set ambient intensity (0-1)\n"
4233 "diffuse n : set diffuse intensity (0-1)\n"
4234 "specular n : set specular intensity (0-1)\n"
4235 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4236 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4237 "<nothing> : print light properties to console\n"
4241 void R_Shadow_EditLights_CopyInfo_f(void)
4243 if (!r_editlights.integer)
4245 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4248 if (!r_shadow_selectedlight)
4250 Con_Print("No selected light.\n");
4253 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4254 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4255 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4256 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4257 if (r_shadow_selectedlight->cubemapname)
4258 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4260 r_shadow_bufferlight.cubemapname[0] = 0;
4261 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4262 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4263 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4264 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4265 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4266 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4267 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4270 void R_Shadow_EditLights_PasteInfo_f(void)
4272 if (!r_editlights.integer)
4274 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4277 if (!r_shadow_selectedlight)
4279 Con_Print("No selected light.\n");
4282 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);
4285 void R_Shadow_EditLights_Init(void)
4287 Cvar_RegisterVariable(&r_editlights);
4288 Cvar_RegisterVariable(&r_editlights_cursordistance);
4289 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4290 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4291 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4292 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4293 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4294 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4295 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4296 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4297 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4298 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4299 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4300 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4301 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4302 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4303 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4304 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4305 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4306 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);