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 return cubemaps[i].texture;
3136 void R_Shadow_FreeCubemaps(void)
3139 R_FreeTexturePool(&r_shadow_filters_texturepool);
3142 dlight_t *R_Shadow_NewWorldLight(void)
3145 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3146 light->next = r_shadow_worldlightchain;
3147 r_shadow_worldlightchain = light;
3151 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)
3153 VectorCopy(origin, light->origin);
3154 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3155 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3156 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3157 light->color[0] = max(color[0], 0);
3158 light->color[1] = max(color[1], 0);
3159 light->color[2] = max(color[2], 0);
3160 light->radius = max(radius, 0);
3161 light->style = style;
3162 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3164 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3167 light->shadow = shadowenable;
3168 light->corona = corona;
3171 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3172 light->coronasizescale = coronasizescale;
3173 light->ambientscale = ambientscale;
3174 light->diffusescale = diffusescale;
3175 light->specularscale = specularscale;
3176 light->flags = flags;
3177 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3179 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3182 void R_Shadow_FreeWorldLight(dlight_t *light)
3184 dlight_t **lightpointer;
3185 R_RTLight_Uncompile(&light->rtlight);
3186 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3187 if (*lightpointer != light)
3188 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3189 *lightpointer = light->next;
3193 void R_Shadow_ClearWorldLights(void)
3195 while (r_shadow_worldlightchain)
3196 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3197 r_shadow_selectedlight = NULL;
3198 R_Shadow_FreeCubemaps();
3201 void R_Shadow_SelectLight(dlight_t *light)
3203 if (r_shadow_selectedlight)
3204 r_shadow_selectedlight->selected = false;
3205 r_shadow_selectedlight = light;
3206 if (r_shadow_selectedlight)
3207 r_shadow_selectedlight->selected = true;
3210 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3212 float scale = r_editlights_cursorgrid.value * 0.5f;
3213 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);
3216 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3219 const dlight_t *light;
3222 if (light->selected)
3223 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3226 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);
3229 void R_Shadow_DrawLightSprites(void)
3235 for (i = 0;i < 5;i++)
3237 lighttextures[i] = NULL;
3238 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3239 lighttextures[i] = pic->tex;
3242 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3243 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3244 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3247 void R_Shadow_SelectLightInView(void)
3249 float bestrating, rating, temp[3];
3250 dlight_t *best, *light;
3253 for (light = r_shadow_worldlightchain;light;light = light->next)
3255 VectorSubtract(light->origin, r_vieworigin, temp);
3256 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3259 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3260 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3262 bestrating = rating;
3267 R_Shadow_SelectLight(best);
3270 void R_Shadow_LoadWorldLights(void)
3272 int n, a, style, shadow, flags;
3273 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3274 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3275 if (r_refdef.worldmodel == NULL)
3277 Con_Print("No map loaded.\n");
3280 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3281 strlcat (name, ".rtlights", sizeof (name));
3282 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3292 for (;COM_Parse(t, true) && strcmp(
3293 if (COM_Parse(t, true))
3295 if (com_token[0] == '!')
3298 origin[0] = atof(com_token+1);
3301 origin[0] = atof(com_token);
3306 while (*s && *s != '\n' && *s != '\r')
3312 // check for modifier flags
3319 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);
3322 flags = LIGHTFLAG_REALTIMEMODE;
3330 coronasizescale = 0.25f;
3332 VectorClear(angles);
3335 if (a < 9 || !strcmp(cubemapname, "\"\""))
3337 // remove quotes on cubemapname
3338 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3340 cubemapname[strlen(cubemapname)-1] = 0;
3341 strcpy(cubemapname, cubemapname + 1);
3345 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);
3348 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3356 Con_Printf("invalid rtlights file \"%s\"\n", name);
3357 Mem_Free(lightsstring);
3361 void R_Shadow_SaveWorldLights(void)
3364 int bufchars, bufmaxchars;
3366 char name[MAX_QPATH];
3368 if (!r_shadow_worldlightchain)
3370 if (r_refdef.worldmodel == NULL)
3372 Con_Print("No map loaded.\n");
3375 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3376 strlcat (name, ".rtlights", sizeof (name));
3377 bufchars = bufmaxchars = 0;
3379 for (light = r_shadow_worldlightchain;light;light = light->next)
3381 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3382 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);
3383 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3384 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]);
3386 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);
3387 if (bufchars + (int) strlen(line) > bufmaxchars)
3389 bufmaxchars = bufchars + strlen(line) + 2048;
3391 buf = Mem_Alloc(tempmempool, bufmaxchars);
3395 memcpy(buf, oldbuf, bufchars);
3401 memcpy(buf + bufchars, line, strlen(line));
3402 bufchars += strlen(line);
3406 FS_WriteFile(name, buf, bufchars);
3411 void R_Shadow_LoadLightsFile(void)
3414 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3415 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3416 if (r_refdef.worldmodel == NULL)
3418 Con_Print("No map loaded.\n");
3421 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3422 strlcat (name, ".lights", sizeof (name));
3423 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3431 while (*s && *s != '\n' && *s != '\r')
3437 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);
3441 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);
3444 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3445 radius = bound(15, radius, 4096);
3446 VectorScale(color, (2.0f / (8388608.0f)), color);
3447 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3455 Con_Printf("invalid lights file \"%s\"\n", name);
3456 Mem_Free(lightsstring);
3460 // tyrlite/hmap2 light types in the delay field
3461 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3463 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3465 int entnum, style, islight, skin, pflags, effects, type, n;
3468 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3469 char key[256], value[1024];
3471 if (r_refdef.worldmodel == NULL)
3473 Con_Print("No map loaded.\n");
3476 // try to load a .ent file first
3477 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3478 strlcat (key, ".ent", sizeof (key));
3479 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true);
3480 // and if that is not found, fall back to the bsp file entity string
3482 data = r_refdef.worldmodel->brush.entities;
3485 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3487 type = LIGHTTYPE_MINUSX;
3488 origin[0] = origin[1] = origin[2] = 0;
3489 originhack[0] = originhack[1] = originhack[2] = 0;
3490 angles[0] = angles[1] = angles[2] = 0;
3491 color[0] = color[1] = color[2] = 1;
3492 light[0] = light[1] = light[2] = 1;light[3] = 300;
3493 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3503 if (!COM_ParseToken(&data, false))
3505 if (com_token[0] == '}')
3506 break; // end of entity
3507 if (com_token[0] == '_')
3508 strcpy(key, com_token + 1);
3510 strcpy(key, com_token);
3511 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3512 key[strlen(key)-1] = 0;
3513 if (!COM_ParseToken(&data, false))
3515 strcpy(value, com_token);
3517 // now that we have the key pair worked out...
3518 if (!strcmp("light", key))
3520 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3524 light[0] = vec[0] * (1.0f / 256.0f);
3525 light[1] = vec[0] * (1.0f / 256.0f);
3526 light[2] = vec[0] * (1.0f / 256.0f);
3532 light[0] = vec[0] * (1.0f / 255.0f);
3533 light[1] = vec[1] * (1.0f / 255.0f);
3534 light[2] = vec[2] * (1.0f / 255.0f);
3538 else if (!strcmp("delay", key))
3540 else if (!strcmp("origin", key))
3541 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3542 else if (!strcmp("angle", key))
3543 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3544 else if (!strcmp("angles", key))
3545 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3546 else if (!strcmp("color", key))
3547 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3548 else if (!strcmp("wait", key))
3549 fadescale = atof(value);
3550 else if (!strcmp("classname", key))
3552 if (!strncmp(value, "light", 5))
3555 if (!strcmp(value, "light_fluoro"))
3560 overridecolor[0] = 1;
3561 overridecolor[1] = 1;
3562 overridecolor[2] = 1;
3564 if (!strcmp(value, "light_fluorospark"))
3569 overridecolor[0] = 1;
3570 overridecolor[1] = 1;
3571 overridecolor[2] = 1;
3573 if (!strcmp(value, "light_globe"))
3578 overridecolor[0] = 1;
3579 overridecolor[1] = 0.8;
3580 overridecolor[2] = 0.4;
3582 if (!strcmp(value, "light_flame_large_yellow"))
3587 overridecolor[0] = 1;
3588 overridecolor[1] = 0.5;
3589 overridecolor[2] = 0.1;
3591 if (!strcmp(value, "light_flame_small_yellow"))
3596 overridecolor[0] = 1;
3597 overridecolor[1] = 0.5;
3598 overridecolor[2] = 0.1;
3600 if (!strcmp(value, "light_torch_small_white"))
3605 overridecolor[0] = 1;
3606 overridecolor[1] = 0.5;
3607 overridecolor[2] = 0.1;
3609 if (!strcmp(value, "light_torch_small_walltorch"))
3614 overridecolor[0] = 1;
3615 overridecolor[1] = 0.5;
3616 overridecolor[2] = 0.1;
3620 else if (!strcmp("style", key))
3621 style = atoi(value);
3622 else if (r_refdef.worldmodel->type == mod_brushq3)
3624 if (!strcmp("scale", key))
3625 lightscale = atof(value);
3626 if (!strcmp("fade", key))
3627 fadescale = atof(value);
3629 else if (!strcmp("skin", key))
3630 skin = (int)atof(value);
3631 else if (!strcmp("pflags", key))
3632 pflags = (int)atof(value);
3633 else if (!strcmp("effects", key))
3634 effects = (int)atof(value);
3638 if (lightscale <= 0)
3642 if (color[0] == color[1] && color[0] == color[2])
3644 color[0] *= overridecolor[0];
3645 color[1] *= overridecolor[1];
3646 color[2] *= overridecolor[2];
3648 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3649 color[0] = color[0] * light[0];
3650 color[1] = color[1] * light[1];
3651 color[2] = color[2] * light[2];
3654 case LIGHTTYPE_MINUSX:
3656 case LIGHTTYPE_RECIPX:
3658 VectorScale(color, (1.0f / 16.0f), color);
3660 case LIGHTTYPE_RECIPXX:
3662 VectorScale(color, (1.0f / 16.0f), color);
3665 case LIGHTTYPE_NONE:
3669 case LIGHTTYPE_MINUSXX:
3672 VectorAdd(origin, originhack, origin);
3674 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);
3677 Mem_Free(entfiledata);
3681 void R_Shadow_SetCursorLocationForView(void)
3684 vec3_t dest, endpos;
3686 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3687 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3688 if (trace.fraction < 1)
3690 dist = trace.fraction * r_editlights_cursordistance.value;
3691 push = r_editlights_cursorpushback.value;
3695 VectorMA(trace.endpos, push, r_viewforward, endpos);
3696 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3698 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3699 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3700 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3703 void R_Shadow_UpdateWorldLightSelection(void)
3705 if (r_editlights.integer)
3707 R_Shadow_SetCursorLocationForView();
3708 R_Shadow_SelectLightInView();
3709 R_Shadow_DrawLightSprites();
3712 R_Shadow_SelectLight(NULL);
3715 void R_Shadow_EditLights_Clear_f(void)
3717 R_Shadow_ClearWorldLights();
3720 void R_Shadow_EditLights_Reload_f(void)
3722 if (!r_refdef.worldmodel)
3724 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3725 R_Shadow_ClearWorldLights();
3726 R_Shadow_LoadWorldLights();
3727 if (r_shadow_worldlightchain == NULL)
3729 R_Shadow_LoadLightsFile();
3730 if (r_shadow_worldlightchain == NULL)
3731 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3735 void R_Shadow_EditLights_Save_f(void)
3737 if (!r_refdef.worldmodel)
3739 R_Shadow_SaveWorldLights();
3742 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3744 R_Shadow_ClearWorldLights();
3745 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3748 void R_Shadow_EditLights_ImportLightsFile_f(void)
3750 R_Shadow_ClearWorldLights();
3751 R_Shadow_LoadLightsFile();
3754 void R_Shadow_EditLights_Spawn_f(void)
3757 if (!r_editlights.integer)
3759 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3762 if (Cmd_Argc() != 1)
3764 Con_Print("r_editlights_spawn does not take parameters\n");
3767 color[0] = color[1] = color[2] = 1;
3768 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3771 void R_Shadow_EditLights_Edit_f(void)
3773 vec3_t origin, angles, color;
3774 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3775 int style, shadows, flags, normalmode, realtimemode;
3776 char cubemapname[1024];
3777 if (!r_editlights.integer)
3779 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3782 if (!r_shadow_selectedlight)
3784 Con_Print("No selected light.\n");
3787 VectorCopy(r_shadow_selectedlight->origin, origin);
3788 VectorCopy(r_shadow_selectedlight->angles, angles);
3789 VectorCopy(r_shadow_selectedlight->color, color);
3790 radius = r_shadow_selectedlight->radius;
3791 style = r_shadow_selectedlight->style;
3792 if (r_shadow_selectedlight->cubemapname)
3793 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3796 shadows = r_shadow_selectedlight->shadow;
3797 corona = r_shadow_selectedlight->corona;
3798 coronasizescale = r_shadow_selectedlight->coronasizescale;
3799 ambientscale = r_shadow_selectedlight->ambientscale;
3800 diffusescale = r_shadow_selectedlight->diffusescale;
3801 specularscale = r_shadow_selectedlight->specularscale;
3802 flags = r_shadow_selectedlight->flags;
3803 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3804 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3805 if (!strcmp(Cmd_Argv(1), "origin"))
3807 if (Cmd_Argc() != 5)
3809 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3812 origin[0] = atof(Cmd_Argv(2));
3813 origin[1] = atof(Cmd_Argv(3));
3814 origin[2] = atof(Cmd_Argv(4));
3816 else if (!strcmp(Cmd_Argv(1), "originx"))
3818 if (Cmd_Argc() != 3)
3820 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3823 origin[0] = atof(Cmd_Argv(2));
3825 else if (!strcmp(Cmd_Argv(1), "originy"))
3827 if (Cmd_Argc() != 3)
3829 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3832 origin[1] = atof(Cmd_Argv(2));
3834 else if (!strcmp(Cmd_Argv(1), "originz"))
3836 if (Cmd_Argc() != 3)
3838 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3841 origin[2] = atof(Cmd_Argv(2));
3843 else if (!strcmp(Cmd_Argv(1), "move"))
3845 if (Cmd_Argc() != 5)
3847 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3850 origin[0] += atof(Cmd_Argv(2));
3851 origin[1] += atof(Cmd_Argv(3));
3852 origin[2] += atof(Cmd_Argv(4));
3854 else if (!strcmp(Cmd_Argv(1), "movex"))
3856 if (Cmd_Argc() != 3)
3858 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3861 origin[0] += atof(Cmd_Argv(2));
3863 else if (!strcmp(Cmd_Argv(1), "movey"))
3865 if (Cmd_Argc() != 3)
3867 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3870 origin[1] += atof(Cmd_Argv(2));
3872 else if (!strcmp(Cmd_Argv(1), "movez"))
3874 if (Cmd_Argc() != 3)
3876 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3879 origin[2] += atof(Cmd_Argv(2));
3881 else if (!strcmp(Cmd_Argv(1), "angles"))
3883 if (Cmd_Argc() != 5)
3885 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3888 angles[0] = atof(Cmd_Argv(2));
3889 angles[1] = atof(Cmd_Argv(3));
3890 angles[2] = atof(Cmd_Argv(4));
3892 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3894 if (Cmd_Argc() != 3)
3896 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3899 angles[0] = atof(Cmd_Argv(2));
3901 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3903 if (Cmd_Argc() != 3)
3905 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3908 angles[1] = atof(Cmd_Argv(2));
3910 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3912 if (Cmd_Argc() != 3)
3914 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3917 angles[2] = atof(Cmd_Argv(2));
3919 else if (!strcmp(Cmd_Argv(1), "color"))
3921 if (Cmd_Argc() != 5)
3923 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3926 color[0] = atof(Cmd_Argv(2));
3927 color[1] = atof(Cmd_Argv(3));
3928 color[2] = atof(Cmd_Argv(4));
3930 else if (!strcmp(Cmd_Argv(1), "radius"))
3932 if (Cmd_Argc() != 3)
3934 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3937 radius = atof(Cmd_Argv(2));
3939 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3941 if (Cmd_Argc() == 3)
3943 double scale = atof(Cmd_Argv(2));
3950 if (Cmd_Argc() != 5)
3952 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3955 color[0] *= atof(Cmd_Argv(2));
3956 color[1] *= atof(Cmd_Argv(3));
3957 color[2] *= atof(Cmd_Argv(4));
3960 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3962 if (Cmd_Argc() != 3)
3964 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3967 radius *= atof(Cmd_Argv(2));
3969 else if (!strcmp(Cmd_Argv(1), "style"))
3971 if (Cmd_Argc() != 3)
3973 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3976 style = atoi(Cmd_Argv(2));
3978 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3982 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3985 if (Cmd_Argc() == 3)
3986 strcpy(cubemapname, Cmd_Argv(2));
3990 else if (!strcmp(Cmd_Argv(1), "shadows"))
3992 if (Cmd_Argc() != 3)
3994 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3997 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3999 else if (!strcmp(Cmd_Argv(1), "corona"))
4001 if (Cmd_Argc() != 3)
4003 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4006 corona = atof(Cmd_Argv(2));
4008 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4010 if (Cmd_Argc() != 3)
4012 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4015 coronasizescale = atof(Cmd_Argv(2));
4017 else if (!strcmp(Cmd_Argv(1), "ambient"))
4019 if (Cmd_Argc() != 3)
4021 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4024 ambientscale = atof(Cmd_Argv(2));
4026 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4028 if (Cmd_Argc() != 3)
4030 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4033 diffusescale = atof(Cmd_Argv(2));
4035 else if (!strcmp(Cmd_Argv(1), "specular"))
4037 if (Cmd_Argc() != 3)
4039 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4042 specularscale = atof(Cmd_Argv(2));
4044 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4046 if (Cmd_Argc() != 3)
4048 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4051 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4053 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4055 if (Cmd_Argc() != 3)
4057 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4060 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4064 Con_Print("usage: r_editlights_edit [property] [value]\n");
4065 Con_Print("Selected light's properties:\n");
4066 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4067 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4068 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4069 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4070 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4071 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4072 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4073 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4074 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4075 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4076 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4077 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4078 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4079 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4082 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4083 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4086 void R_Shadow_EditLights_EditAll_f(void)
4090 if (!r_editlights.integer)
4092 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4096 for (light = r_shadow_worldlightchain;light;light = light->next)
4098 R_Shadow_SelectLight(light);
4099 R_Shadow_EditLights_Edit_f();
4103 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4105 int lightnumber, lightcount;
4109 if (!r_editlights.integer)
4115 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4116 if (light == r_shadow_selectedlight)
4117 lightnumber = lightcount;
4118 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;
4119 if (r_shadow_selectedlight == NULL)
4121 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4122 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;
4123 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;
4124 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;
4125 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4126 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4127 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4128 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;
4129 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4130 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4131 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4132 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4133 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4134 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;
4135 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;
4138 void R_Shadow_EditLights_ToggleShadow_f(void)
4140 if (!r_editlights.integer)
4142 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4145 if (!r_shadow_selectedlight)
4147 Con_Print("No selected light.\n");
4150 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);
4153 void R_Shadow_EditLights_ToggleCorona_f(void)
4155 if (!r_editlights.integer)
4157 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4160 if (!r_shadow_selectedlight)
4162 Con_Print("No selected light.\n");
4165 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);
4168 void R_Shadow_EditLights_Remove_f(void)
4170 if (!r_editlights.integer)
4172 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4175 if (!r_shadow_selectedlight)
4177 Con_Print("No selected light.\n");
4180 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4181 r_shadow_selectedlight = NULL;
4184 void R_Shadow_EditLights_Help_f(void)
4187 "Documentation on r_editlights system:\n"
4189 "r_editlights : enable/disable editing mode\n"
4190 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4191 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4192 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4193 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4194 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4196 "r_editlights_help : this help\n"
4197 "r_editlights_clear : remove all lights\n"
4198 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4199 "r_editlights_save : save to .rtlights file\n"
4200 "r_editlights_spawn : create a light with default settings\n"
4201 "r_editlights_edit command : edit selected light - more documentation below\n"
4202 "r_editlights_remove : remove selected light\n"
4203 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4204 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4205 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4207 "origin x y z : set light location\n"
4208 "originx x: set x component of light location\n"
4209 "originy y: set y component of light location\n"
4210 "originz z: set z component of light location\n"
4211 "move x y z : adjust light location\n"
4212 "movex x: adjust x component of light location\n"
4213 "movey y: adjust y component of light location\n"
4214 "movez z: adjust z component of light location\n"
4215 "angles x y z : set light angles\n"
4216 "anglesx x: set x component of light angles\n"
4217 "anglesy y: set y component of light angles\n"
4218 "anglesz z: set z component of light angles\n"
4219 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4220 "radius radius : set radius (size) of light\n"
4221 "colorscale grey : multiply color of light (1 does nothing)\n"
4222 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4223 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4224 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4225 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4226 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4227 "shadows 1/0 : turn on/off shadows\n"
4228 "corona n : set corona intensity\n"
4229 "coronasize n : set corona size (0-1)\n"
4230 "ambient n : set ambient intensity (0-1)\n"
4231 "diffuse n : set diffuse intensity (0-1)\n"
4232 "specular n : set specular intensity (0-1)\n"
4233 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4234 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4235 "<nothing> : print light properties to console\n"
4239 void R_Shadow_EditLights_CopyInfo_f(void)
4241 if (!r_editlights.integer)
4243 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4246 if (!r_shadow_selectedlight)
4248 Con_Print("No selected light.\n");
4251 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4252 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4253 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4254 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4255 if (r_shadow_selectedlight->cubemapname)
4256 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4258 r_shadow_bufferlight.cubemapname[0] = 0;
4259 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4260 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4261 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4262 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4263 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4264 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4265 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4268 void R_Shadow_EditLights_PasteInfo_f(void)
4270 if (!r_editlights.integer)
4272 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4275 if (!r_shadow_selectedlight)
4277 Con_Print("No selected light.\n");
4280 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);
4283 void R_Shadow_EditLights_Init(void)
4285 Cvar_RegisterVariable(&r_editlights);
4286 Cvar_RegisterVariable(&r_editlights_cursordistance);
4287 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4288 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4289 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4290 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4291 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4292 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4293 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4294 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4295 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4296 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4297 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4298 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4299 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4300 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4301 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4302 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4303 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4304 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);