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", "1"};
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"};
235 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
236 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
238 float r_shadow_attenpower, r_shadow_attenscale;
240 rtlight_t *r_shadow_compilingrtlight;
241 dlight_t *r_shadow_worldlightchain;
242 dlight_t *r_shadow_selectedlight;
243 dlight_t r_shadow_bufferlight;
244 vec3_t r_editlights_cursorlocation;
246 rtexture_t *lighttextures[5];
248 extern int con_vislines;
250 typedef struct cubemapinfo_s
257 #define MAX_CUBEMAPS 256
258 static int numcubemaps;
259 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
261 #define SHADERPERMUTATION_SPECULAR (1<<0)
262 #define SHADERPERMUTATION_FOG (1<<1)
263 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
264 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
265 #define SHADERPERMUTATION_SURFACENORMALIZE (1<<4)
266 #define SHADERPERMUTATION_GEFORCEFX (1<<5)
267 #define SHADERPERMUTATION_COUNT (1<<6)
269 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
271 void R_Shadow_UncompileWorldLights(void);
272 void R_Shadow_ClearWorldLights(void);
273 void R_Shadow_SaveWorldLights(void);
274 void R_Shadow_LoadWorldLights(void);
275 void R_Shadow_LoadLightsFile(void);
276 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
277 void R_Shadow_EditLights_Reload_f(void);
278 void R_Shadow_ValidateCvars(void);
279 static void R_Shadow_MakeTextures(void);
280 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
282 const char *builtinshader_light_vert =
283 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
284 "// written by Forest 'LordHavoc' Hale\n"
286 "uniform vec3 LightPosition;\n"
288 "varying vec2 TexCoord;\n"
289 "varying vec3 CubeVector;\n"
290 "varying vec3 LightVector;\n"
292 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
293 "uniform vec3 EyePosition;\n"
294 "varying vec3 EyeVector;\n"
297 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
301 " // copy the surface texcoord\n"
302 " TexCoord = gl_MultiTexCoord0.st;\n"
304 " // transform vertex position into light attenuation/cubemap space\n"
305 " // (-1 to +1 across the light box)\n"
306 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
308 " // transform unnormalized light direction into tangent space\n"
309 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
310 " // normalize it per pixel)\n"
311 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
312 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
313 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
314 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
316 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
317 " // transform unnormalized eye direction into tangent space\n"
318 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
319 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
320 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
321 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
324 " // transform vertex to camera space, using ftransform to match non-VS\n"
326 " gl_Position = ftransform();\n"
330 const char *builtinshader_light_frag =
331 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
332 "// written by Forest 'LordHavoc' Hale\n"
334 "// use half floats on GEFORCEFX for math performance, otherwise don't\n"
335 "#ifndef GEFORCEFX\n"
336 "#define half float\n"
337 "#define hvec2 vec2\n"
338 "#define hvec3 vec3\n"
339 "#define hvec4 vec4\n"
342 "uniform hvec3 LightColor;\n"
343 "#ifdef USEOFFSETMAPPING\n"
344 "uniform half OffsetMapping_Scale;\n"
345 "uniform half OffsetMapping_Bias;\n"
347 "#ifdef USESPECULAR\n"
348 "uniform half SpecularPower;\n"
351 "uniform half FogRangeRecip;\n"
353 "uniform half AmbientScale;\n"
354 "uniform half DiffuseScale;\n"
355 "#ifdef USESPECULAR\n"
356 "uniform half SpecularScale;\n"
359 "uniform sampler2D Texture_Normal;\n"
360 "uniform sampler2D Texture_Color;\n"
361 "#ifdef USESPECULAR\n"
362 "uniform sampler2D Texture_Gloss;\n"
364 "#ifdef USECUBEFILTER\n"
365 "uniform samplerCube Texture_Cube;\n"
368 "uniform sampler2D Texture_FogMask;\n"
371 "varying vec2 TexCoord;\n"
372 "varying vec3 CubeVector;\n"
373 "varying vec3 LightVector;\n"
374 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
375 "varying vec3 EyeVector;\n"
382 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
383 " // center and sharp falloff at the edge, this is about the most efficient\n"
384 " // we can get away with as far as providing illumination.\n"
386 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
387 " // provide significant illumination, large = slow = pain.\n"
388 " half colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
392 " colorscale *= texture2D(Texture_FogMask, hvec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
395 "#ifdef USEOFFSETMAPPING\n"
396 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
397 " hvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
398 " hvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
399 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
400 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
401 "#define TexCoord TexCoordOffset\n"
404 " // get the surface normal\n"
405 "#ifdef SURFACENORMALIZE\n"
406 " hvec3 surfacenormal = normalize(hvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
408 " hvec3 surfacenormal = -1.0 + 2.0 * hvec3(texture2D(Texture_Normal, TexCoord));\n"
411 " // calculate shading\n"
412 " hvec3 diffusenormal = hvec3(normalize(LightVector));\n"
413 " hvec3 color = hvec3(texture2D(Texture_Color, TexCoord)) * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
414 "#ifdef USESPECULAR\n"
415 " hvec3 specularnormal = hvec3(normalize(diffusenormal + hvec3(normalize(EyeVector))));\n"
416 " color += hvec3(texture2D(Texture_Gloss, TexCoord)) * (SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower));\n"
419 "#ifdef USECUBEFILTER\n"
420 " // apply light cubemap filter\n"
421 " color *= hvec3(textureCube(Texture_Cube, CubeVector));\n"
424 " // calculate fragment color (apply light color and attenuation/fog scaling)\n"
425 " gl_FragColor = hvec4(color * LightColor * colorscale, 1);\n"
429 void r_shadow_start(void)
432 // if not a GeForce FX, turn off the lowquality cvar
433 if (strncmp(gl_renderer, "GeForce FX ", strlen("GeForce FX ")))
434 Cvar_SetValue("r_shadow_glsl_geforcefxlowquality", 0);
435 // allocate vertex processing arrays
437 r_shadow_attenuation2dtexture = NULL;
438 r_shadow_attenuation3dtexture = NULL;
439 r_shadow_texturepool = NULL;
440 r_shadow_filters_texturepool = NULL;
441 R_Shadow_ValidateCvars();
442 R_Shadow_MakeTextures();
443 maxshadowelements = 0;
444 shadowelements = NULL;
452 shadowmarklist = NULL;
454 r_shadow_buffer_numleafpvsbytes = 0;
455 r_shadow_buffer_leafpvs = NULL;
456 r_shadow_buffer_leaflist = NULL;
457 r_shadow_buffer_numsurfacepvsbytes = 0;
458 r_shadow_buffer_surfacepvs = NULL;
459 r_shadow_buffer_surfacelist = NULL;
460 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
461 r_shadow_program_light[i] = 0;
462 if (gl_support_fragment_shader)
464 char *vertstring, *fragstring;
465 int vertstrings_count;
466 int fragstrings_count;
467 const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
468 const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
469 vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false);
470 fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false);
471 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
473 vertstrings_count = 0;
474 fragstrings_count = 0;
475 if (i & SHADERPERMUTATION_SPECULAR)
477 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
478 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
480 if (i & SHADERPERMUTATION_FOG)
482 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
483 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
485 if (i & SHADERPERMUTATION_CUBEFILTER)
487 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
488 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
490 if (i & SHADERPERMUTATION_OFFSETMAPPING)
492 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
493 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
495 if (i & SHADERPERMUTATION_SURFACENORMALIZE)
497 vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
498 fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
500 if (i & SHADERPERMUTATION_GEFORCEFX)
502 vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
503 fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
505 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
506 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
507 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
508 if (!r_shadow_program_light[i])
510 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
513 qglUseProgramObjectARB(r_shadow_program_light[i]);
514 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
515 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
516 if (i & SHADERPERMUTATION_SPECULAR)
518 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
520 if (i & SHADERPERMUTATION_CUBEFILTER)
522 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
524 if (i & SHADERPERMUTATION_FOG)
526 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
529 qglUseProgramObjectARB(0);
531 Mem_Free(fragstring);
533 Mem_Free(vertstring);
537 void r_shadow_shutdown(void)
540 R_Shadow_UncompileWorldLights();
541 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
543 if (r_shadow_program_light[i])
545 GL_Backend_FreeProgram(r_shadow_program_light[i]);
546 r_shadow_program_light[i] = 0;
550 r_shadow_attenuation2dtexture = NULL;
551 r_shadow_attenuation3dtexture = NULL;
552 R_FreeTexturePool(&r_shadow_texturepool);
553 R_FreeTexturePool(&r_shadow_filters_texturepool);
554 maxshadowelements = 0;
556 Mem_Free(shadowelements);
557 shadowelements = NULL;
560 Mem_Free(vertexupdate);
563 Mem_Free(vertexremap);
569 Mem_Free(shadowmark);
572 Mem_Free(shadowmarklist);
573 shadowmarklist = NULL;
575 r_shadow_buffer_numleafpvsbytes = 0;
576 if (r_shadow_buffer_leafpvs)
577 Mem_Free(r_shadow_buffer_leafpvs);
578 r_shadow_buffer_leafpvs = NULL;
579 if (r_shadow_buffer_leaflist)
580 Mem_Free(r_shadow_buffer_leaflist);
581 r_shadow_buffer_leaflist = NULL;
582 r_shadow_buffer_numsurfacepvsbytes = 0;
583 if (r_shadow_buffer_surfacepvs)
584 Mem_Free(r_shadow_buffer_surfacepvs);
585 r_shadow_buffer_surfacepvs = NULL;
586 if (r_shadow_buffer_surfacelist)
587 Mem_Free(r_shadow_buffer_surfacelist);
588 r_shadow_buffer_surfacelist = NULL;
591 void r_shadow_newmap(void)
595 void R_Shadow_Help_f(void)
598 "Documentation on r_shadow system:\n"
600 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
601 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
602 "r_shadow_debuglight : render only this light number (-1 = all)\n"
603 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
604 "r_shadow_gloss2intensity : brightness of forced gloss\n"
605 "r_shadow_glossintensity : brightness of textured gloss\n"
606 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
607 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
608 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
609 "r_shadow_portallight : use portal visibility for static light precomputation\n"
610 "r_shadow_projectdistance : shadow volume projection distance\n"
611 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
612 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
613 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
614 "r_shadow_realtime_world : use high quality world lighting mode\n"
615 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
616 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
617 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
618 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
619 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
620 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
621 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
622 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
623 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
624 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
625 "r_shadow_glsl_geforcefxlowquality : use lower quality lighting\n"
626 "r_shadow_glsl_surfacenormalize : makes bumpmapping slightly higher quality\n"
627 "r_shadow_scissor : use scissor optimization\n"
628 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
629 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
630 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
631 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
632 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
633 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
635 "r_shadow_help : this help\n"
639 void R_Shadow_Init(void)
641 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
642 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
643 Cvar_RegisterVariable(&r_shadow_debuglight);
644 Cvar_RegisterVariable(&r_shadow_gloss);
645 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
646 Cvar_RegisterVariable(&r_shadow_glossintensity);
647 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
648 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
649 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
650 Cvar_RegisterVariable(&r_shadow_portallight);
651 Cvar_RegisterVariable(&r_shadow_projectdistance);
652 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
653 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
654 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
655 Cvar_RegisterVariable(&r_shadow_realtime_world);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
660 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
661 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
662 Cvar_RegisterVariable(&r_shadow_scissor);
663 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
664 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
665 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
666 Cvar_RegisterVariable(&r_shadow_texture3d);
667 Cvar_RegisterVariable(&r_shadow_visiblelighting);
668 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
669 Cvar_RegisterVariable(&r_shadow_glsl);
670 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
671 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
672 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
673 Cvar_RegisterVariable(&r_shadow_glsl_geforcefxlowquality);
674 Cvar_RegisterVariable(&r_shadow_glsl_surfacenormalize);
675 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
676 if (gamemode == GAME_TENEBRAE)
678 Cvar_SetValue("r_shadow_gloss", 2);
679 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
681 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
682 R_Shadow_EditLights_Init();
683 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
684 r_shadow_worldlightchain = NULL;
685 maxshadowelements = 0;
686 shadowelements = NULL;
694 shadowmarklist = NULL;
696 r_shadow_buffer_numleafpvsbytes = 0;
697 r_shadow_buffer_leafpvs = NULL;
698 r_shadow_buffer_leaflist = NULL;
699 r_shadow_buffer_numsurfacepvsbytes = 0;
700 r_shadow_buffer_surfacepvs = NULL;
701 r_shadow_buffer_surfacelist = NULL;
702 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
705 matrix4x4_t matrix_attenuationxyz =
708 {0.5, 0.0, 0.0, 0.5},
709 {0.0, 0.5, 0.0, 0.5},
710 {0.0, 0.0, 0.5, 0.5},
715 matrix4x4_t matrix_attenuationz =
718 {0.0, 0.0, 0.5, 0.5},
719 {0.0, 0.0, 0.0, 0.5},
720 {0.0, 0.0, 0.0, 0.5},
725 int *R_Shadow_ResizeShadowElements(int numtris)
727 // make sure shadowelements is big enough for this volume
728 if (maxshadowelements < numtris * 24)
730 maxshadowelements = numtris * 24;
732 Mem_Free(shadowelements);
733 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
735 return shadowelements;
738 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
740 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
741 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
742 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
744 if (r_shadow_buffer_leafpvs)
745 Mem_Free(r_shadow_buffer_leafpvs);
746 if (r_shadow_buffer_leaflist)
747 Mem_Free(r_shadow_buffer_leaflist);
748 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
749 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
750 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
752 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
754 if (r_shadow_buffer_surfacepvs)
755 Mem_Free(r_shadow_buffer_surfacepvs);
756 if (r_shadow_buffer_surfacelist)
757 Mem_Free(r_shadow_buffer_surfacelist);
758 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
759 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
760 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
764 void R_Shadow_PrepareShadowMark(int numtris)
766 // make sure shadowmark is big enough for this volume
767 if (maxshadowmark < numtris)
769 maxshadowmark = numtris;
771 Mem_Free(shadowmark);
773 Mem_Free(shadowmarklist);
774 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
775 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
779 // if shadowmarkcount wrapped we clear the array and adjust accordingly
780 if (shadowmarkcount == 0)
783 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
788 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)
791 int outtriangles = 0, outvertices = 0;
795 if (maxvertexupdate < innumvertices)
797 maxvertexupdate = innumvertices;
799 Mem_Free(vertexupdate);
801 Mem_Free(vertexremap);
802 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
803 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
807 if (vertexupdatenum == 0)
810 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
811 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
814 for (i = 0;i < numshadowmarktris;i++)
815 shadowmark[shadowmarktris[i]] = shadowmarkcount;
817 for (i = 0;i < numshadowmarktris;i++)
819 element = inelement3i + shadowmarktris[i] * 3;
820 // make sure the vertices are created
821 for (j = 0;j < 3;j++)
823 if (vertexupdate[element[j]] != vertexupdatenum)
825 float ratio, direction[3];
826 vertexupdate[element[j]] = vertexupdatenum;
827 vertexremap[element[j]] = outvertices;
828 vertex = invertex3f + element[j] * 3;
829 // project one copy of the vertex to the sphere radius of the light
830 // (FIXME: would projecting it to the light box be better?)
831 VectorSubtract(vertex, projectorigin, direction);
832 ratio = projectdistance / VectorLength(direction);
833 VectorCopy(vertex, outvertex3f);
834 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
841 for (i = 0;i < numshadowmarktris;i++)
843 int remappedelement[3];
845 const int *neighbortriangle;
847 markindex = shadowmarktris[i] * 3;
848 element = inelement3i + markindex;
849 neighbortriangle = inneighbor3i + markindex;
850 // output the front and back triangles
851 outelement3i[0] = vertexremap[element[0]];
852 outelement3i[1] = vertexremap[element[1]];
853 outelement3i[2] = vertexremap[element[2]];
854 outelement3i[3] = vertexremap[element[2]] + 1;
855 outelement3i[4] = vertexremap[element[1]] + 1;
856 outelement3i[5] = vertexremap[element[0]] + 1;
860 // output the sides (facing outward from this triangle)
861 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
863 remappedelement[0] = vertexremap[element[0]];
864 remappedelement[1] = vertexremap[element[1]];
865 outelement3i[0] = remappedelement[1];
866 outelement3i[1] = remappedelement[0];
867 outelement3i[2] = remappedelement[0] + 1;
868 outelement3i[3] = remappedelement[1];
869 outelement3i[4] = remappedelement[0] + 1;
870 outelement3i[5] = remappedelement[1] + 1;
875 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
877 remappedelement[1] = vertexremap[element[1]];
878 remappedelement[2] = vertexremap[element[2]];
879 outelement3i[0] = remappedelement[2];
880 outelement3i[1] = remappedelement[1];
881 outelement3i[2] = remappedelement[1] + 1;
882 outelement3i[3] = remappedelement[2];
883 outelement3i[4] = remappedelement[1] + 1;
884 outelement3i[5] = remappedelement[2] + 1;
889 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
891 remappedelement[0] = vertexremap[element[0]];
892 remappedelement[2] = vertexremap[element[2]];
893 outelement3i[0] = remappedelement[0];
894 outelement3i[1] = remappedelement[2];
895 outelement3i[2] = remappedelement[2] + 1;
896 outelement3i[3] = remappedelement[0];
897 outelement3i[4] = remappedelement[2] + 1;
898 outelement3i[5] = remappedelement[0] + 1;
905 *outnumvertices = outvertices;
909 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)
912 if (projectdistance < 0.1)
914 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
917 if (!numverts || !nummarktris)
919 // make sure shadowelements is big enough for this volume
920 if (maxshadowelements < nummarktris * 24)
921 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
922 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
923 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
926 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)
931 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
933 tend = firsttriangle + numtris;
934 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
935 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
936 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
938 // surface box entirely inside light box, no box cull
939 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
940 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
941 shadowmarklist[numshadowmark++] = t;
945 // surface box not entirely inside light box, cull each triangle
946 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
948 v[0] = invertex3f + e[0] * 3;
949 v[1] = invertex3f + e[1] * 3;
950 v[2] = invertex3f + e[2] * 3;
951 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
952 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
953 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
954 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
955 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
956 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
957 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
958 shadowmarklist[numshadowmark++] = t;
963 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
966 if (r_shadow_compilingrtlight)
968 // if we're compiling an rtlight, capture the mesh
969 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
972 memset(&m, 0, sizeof(m));
973 m.pointer_vertex = vertex3f;
975 GL_LockArrays(0, numvertices);
976 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
978 // decrement stencil if backface is behind depthbuffer
979 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
980 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
981 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
983 c_rt_shadowtris += numtriangles;
984 // increment stencil if frontface is behind depthbuffer
985 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
986 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
988 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
990 c_rt_shadowtris += numtriangles;
994 static void R_Shadow_MakeTextures(void)
997 float v[3], intensity;
999 R_FreeTexturePool(&r_shadow_texturepool);
1000 r_shadow_texturepool = R_AllocTexturePool();
1001 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
1002 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
1003 #define ATTEN2DSIZE 64
1004 #define ATTEN3DSIZE 32
1005 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
1006 for (y = 0;y < ATTEN2DSIZE;y++)
1008 for (x = 0;x < ATTEN2DSIZE;x++)
1010 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1011 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1013 intensity = 1.0f - sqrt(DotProduct(v, v));
1015 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1016 d = bound(0, intensity, 255);
1017 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1018 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1019 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1020 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1023 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1024 if (r_shadow_texture3d.integer)
1026 for (z = 0;z < ATTEN3DSIZE;z++)
1028 for (y = 0;y < ATTEN3DSIZE;y++)
1030 for (x = 0;x < ATTEN3DSIZE;x++)
1032 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1033 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1034 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1035 intensity = 1.0f - sqrt(DotProduct(v, v));
1037 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1038 d = bound(0, intensity, 255);
1039 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1040 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1041 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1042 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1046 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1051 void R_Shadow_ValidateCvars(void)
1053 if (r_shadow_texture3d.integer && !gl_texture3d)
1054 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1055 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1056 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1059 // light currently being rendered
1060 static rtlight_t *r_shadow_rtlight;
1061 // light filter cubemap being used by the light
1062 static rtexture_t *r_shadow_lightcubemap;
1064 // this is the location of the eye in entity space
1065 static vec3_t r_shadow_entityeyeorigin;
1066 // this is the location of the light in entity space
1067 static vec3_t r_shadow_entitylightorigin;
1068 // this transforms entity coordinates to light filter cubemap coordinates
1069 // (also often used for other purposes)
1070 static matrix4x4_t r_shadow_entitytolight;
1071 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1072 // of attenuation texturing in full 3D (Z result often ignored)
1073 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1074 // this transforms only the Z to S, and T is always 0.5
1075 static matrix4x4_t r_shadow_entitytoattenuationz;
1076 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1077 static vec3_t r_shadow_entitylightcolor;
1079 static int r_shadow_lightpermutation;
1080 static int r_shadow_lightprog;
1082 void R_Shadow_Stage_Begin(void)
1086 R_Shadow_ValidateCvars();
1088 if (!r_shadow_attenuation2dtexture
1089 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1090 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1091 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1092 R_Shadow_MakeTextures();
1094 memset(&m, 0, sizeof(m));
1095 GL_BlendFunc(GL_ONE, GL_ZERO);
1096 GL_DepthMask(false);
1099 GL_Color(0, 0, 0, 1);
1100 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1101 qglEnable(GL_CULL_FACE);
1102 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1103 r_shadowstage = R_SHADOWSTAGE_NONE;
1106 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1108 r_shadow_rtlight = rtlight;
1111 void R_Shadow_Stage_Reset(void)
1114 if (gl_support_stenciltwoside)
1115 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1116 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1118 qglUseProgramObjectARB(0);
1119 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1120 qglBegin(GL_TRIANGLES);
1124 memset(&m, 0, sizeof(m));
1128 void R_Shadow_Stage_StencilShadowVolumes(void)
1130 R_Shadow_Stage_Reset();
1131 GL_Color(1, 1, 1, 1);
1132 GL_ColorMask(0, 0, 0, 0);
1133 GL_BlendFunc(GL_ONE, GL_ZERO);
1134 GL_DepthMask(false);
1136 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1137 //if (r_shadow_shadow_polygonoffset.value != 0)
1139 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1140 // qglEnable(GL_POLYGON_OFFSET_FILL);
1143 // qglDisable(GL_POLYGON_OFFSET_FILL);
1144 qglDepthFunc(GL_LESS);
1145 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1146 qglEnable(GL_STENCIL_TEST);
1147 qglStencilFunc(GL_ALWAYS, 128, ~0);
1148 if (gl_ext_stenciltwoside.integer)
1150 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1151 qglDisable(GL_CULL_FACE);
1152 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1153 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1155 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1156 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1158 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1162 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1163 qglEnable(GL_CULL_FACE);
1165 // this is changed by every shadow render so its value here is unimportant
1166 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1168 GL_Clear(GL_STENCIL_BUFFER_BIT);
1172 void R_Shadow_Stage_Lighting(int stenciltest)
1175 R_Shadow_Stage_Reset();
1176 GL_BlendFunc(GL_ONE, GL_ONE);
1177 GL_DepthMask(false);
1179 qglPolygonOffset(0, 0);
1180 //qglDisable(GL_POLYGON_OFFSET_FILL);
1181 GL_Color(1, 1, 1, 1);
1182 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1183 qglDepthFunc(GL_EQUAL);
1184 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1185 qglEnable(GL_CULL_FACE);
1186 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1187 qglEnable(GL_STENCIL_TEST);
1189 qglDisable(GL_STENCIL_TEST);
1191 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1192 // only draw light where this geometry was already rendered AND the
1193 // stencil is 128 (values other than this mean shadow)
1194 qglStencilFunc(GL_EQUAL, 128, ~0);
1195 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1197 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1198 memset(&m, 0, sizeof(m));
1199 m.pointer_vertex = varray_vertex3f;
1200 m.pointer_texcoord[0] = varray_texcoord2f[0];
1201 m.pointer_texcoord3f[1] = varray_svector3f;
1202 m.pointer_texcoord3f[2] = varray_tvector3f;
1203 m.pointer_texcoord3f[3] = varray_normal3f;
1204 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1205 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1206 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1207 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1208 // TODO: support fog (after renderer is converted to texture fog)
1209 m.tex[4] = R_GetTexture(r_texture_white); // fog
1210 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1212 GL_BlendFunc(GL_ONE, GL_ONE);
1213 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1215 r_shadow_lightpermutation = 0;
1216 // only add a feature to the permutation if that permutation exists
1217 // (otherwise it might end up not using a shader at all, which looks
1218 // worse than using less features)
1219 if (r_shadow_rtlight->specularscale && r_shadow_gloss.integer >= 1 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1220 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1221 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1222 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1223 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1224 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1225 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1226 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1227 if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
1228 r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
1229 if (r_shadow_glsl_geforcefxlowquality.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
1230 r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
1231 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1232 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1233 // TODO: support fog (after renderer is converted to texture fog)
1234 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1236 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1238 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1239 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1240 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1242 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1243 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1245 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1246 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1247 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1249 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1251 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1253 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1254 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1257 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1258 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1260 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1263 void R_Shadow_Stage_VisibleShadowVolumes(void)
1265 R_Shadow_Stage_Reset();
1266 GL_BlendFunc(GL_ONE, GL_ONE);
1267 GL_DepthMask(false);
1268 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1269 qglPolygonOffset(0, 0);
1270 GL_Color(0.0, 0.0125, 0.1, 1);
1271 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1272 qglDepthFunc(GL_GEQUAL);
1273 qglCullFace(GL_FRONT); // this culls back
1274 qglDisable(GL_CULL_FACE);
1275 qglDisable(GL_STENCIL_TEST);
1276 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1279 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1281 R_Shadow_Stage_Reset();
1282 GL_BlendFunc(GL_ONE, GL_ONE);
1283 GL_DepthMask(false);
1284 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1285 qglPolygonOffset(0, 0);
1286 GL_Color(0.1, 0.0125, 0, 1);
1287 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1288 qglDepthFunc(GL_EQUAL);
1289 qglCullFace(GL_FRONT); // this culls back
1290 qglEnable(GL_CULL_FACE);
1292 qglEnable(GL_STENCIL_TEST);
1294 qglDisable(GL_STENCIL_TEST);
1295 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1298 void R_Shadow_Stage_End(void)
1300 R_Shadow_Stage_Reset();
1301 R_Shadow_Stage_ActiveLight(NULL);
1302 GL_BlendFunc(GL_ONE, GL_ZERO);
1305 qglPolygonOffset(0, 0);
1306 //qglDisable(GL_POLYGON_OFFSET_FILL);
1307 GL_Color(1, 1, 1, 1);
1308 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1309 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1310 qglDepthFunc(GL_LEQUAL);
1311 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1312 qglDisable(GL_STENCIL_TEST);
1313 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1314 if (gl_support_stenciltwoside)
1315 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1317 qglStencilFunc(GL_ALWAYS, 128, ~0);
1318 r_shadowstage = R_SHADOWSTAGE_NONE;
1321 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1323 int i, ix1, iy1, ix2, iy2;
1324 float x1, y1, x2, y2;
1327 mplane_t planes[11];
1328 float vertex3f[256*3];
1330 // if view is inside the light box, just say yes it's visible
1331 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1333 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1337 // create a temporary brush describing the area the light can affect in worldspace
1338 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1339 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1340 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1341 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1342 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1343 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1344 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1345 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1346 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1347 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1348 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1350 // turn the brush into a mesh
1351 memset(&mesh, 0, sizeof(rmesh_t));
1352 mesh.maxvertices = 256;
1353 mesh.vertex3f = vertex3f;
1354 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1355 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1357 // if that mesh is empty, the light is not visible at all
1358 if (!mesh.numvertices)
1361 if (!r_shadow_scissor.integer)
1364 // if that mesh is not empty, check what area of the screen it covers
1365 x1 = y1 = x2 = y2 = 0;
1367 for (i = 0;i < mesh.numvertices;i++)
1369 VectorCopy(mesh.vertex3f + i * 3, v);
1370 GL_TransformToScreen(v, v2);
1371 //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]);
1374 if (x1 > v2[0]) x1 = v2[0];
1375 if (x2 < v2[0]) x2 = v2[0];
1376 if (y1 > v2[1]) y1 = v2[1];
1377 if (y2 < v2[1]) y2 = v2[1];
1386 // now convert the scissor rectangle to integer screen coordinates
1391 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1393 // clamp it to the screen
1394 if (ix1 < r_view_x) ix1 = r_view_x;
1395 if (iy1 < r_view_y) iy1 = r_view_y;
1396 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1397 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1399 // if it is inside out, it's not visible
1400 if (ix2 <= ix1 || iy2 <= iy1)
1403 // the light area is visible, set up the scissor rectangle
1404 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1405 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1406 //qglEnable(GL_SCISSOR_TEST);
1411 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1413 float *color4f = varray_color4f;
1414 float dist, dot, intensity, v[3], n[3];
1415 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1417 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1418 if ((dist = DotProduct(v, v)) < 1)
1420 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1421 if ((dot = DotProduct(n, v)) > 0)
1424 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1425 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1426 VectorScale(lightcolor, intensity, color4f);
1431 VectorClear(color4f);
1437 VectorClear(color4f);
1443 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1445 float *color4f = varray_color4f;
1446 float dist, dot, intensity, v[3], n[3];
1447 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1449 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1450 if ((dist = fabs(v[2])) < 1)
1452 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1453 if ((dot = DotProduct(n, v)) > 0)
1455 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1456 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1457 VectorScale(lightcolor, intensity, color4f);
1462 VectorClear(color4f);
1468 VectorClear(color4f);
1474 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
1476 float *color4f = varray_color4f;
1477 float dot, intensity, v[3], n[3];
1478 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1480 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1481 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1482 if ((dot = DotProduct(n, v)) > 0)
1484 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1485 VectorScale(lightcolor, intensity, color4f);
1490 VectorClear(color4f);
1496 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1498 float *color4f = varray_color4f;
1499 float dist, intensity, v[3];
1500 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1502 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1503 if ((dist = DotProduct(v, v)) < 1)
1506 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1507 VectorScale(lightcolor, intensity, color4f);
1512 VectorClear(color4f);
1518 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
1520 float *color4f = varray_color4f;
1521 float dist, intensity, v[3];
1522 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1524 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1525 if ((dist = fabs(v[2])) < 1)
1527 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1528 VectorScale(lightcolor, intensity, color4f);
1533 VectorClear(color4f);
1539 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1540 #define USETEXMATRIX
1542 #ifndef USETEXMATRIX
1543 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1544 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1545 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1549 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1550 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1551 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1558 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1562 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1563 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1571 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)
1575 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1577 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1578 // the cubemap normalizes this for us
1579 out3f[0] = DotProduct(svector3f, lightdir);
1580 out3f[1] = DotProduct(tvector3f, lightdir);
1581 out3f[2] = DotProduct(normal3f, lightdir);
1585 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)
1588 float lightdir[3], eyedir[3], halfdir[3];
1589 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1591 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1592 VectorNormalize(lightdir);
1593 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1594 VectorNormalize(eyedir);
1595 VectorAdd(lightdir, eyedir, halfdir);
1596 // the cubemap normalizes this for us
1597 out3f[0] = DotProduct(svector3f, halfdir);
1598 out3f[1] = DotProduct(tvector3f, halfdir);
1599 out3f[2] = DotProduct(normal3f, halfdir);
1603 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)
1606 float color[3], color2[3], colorscale, specularscale;
1608 // FIXME: support MATERIALFLAG_NODEPTHTEST
1610 basetexture = r_texture_white;
1612 bumptexture = r_texture_blanknormalmap;
1614 lightcolorpants = vec3_origin;
1616 lightcolorshirt = vec3_origin;
1617 if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1618 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
1619 else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
1621 glosstexture = r_texture_white;
1622 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
1626 glosstexture = r_texture_black;
1629 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1631 if (r_shadowstage == R_SHADOWSTAGE_VISIBLELIGHTING)
1634 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1635 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1636 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1638 // TODO: add direct pants/shirt rendering
1639 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1640 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1641 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1642 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1643 if (r_shadow_rtlight->ambientscale)
1645 colorscale = r_shadow_rtlight->ambientscale;
1646 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1649 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1652 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1655 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1660 VectorScale(lightcolorbase, colorscale, color2);
1661 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1664 if (r_shadow_rtlight->diffusescale)
1666 colorscale = r_shadow_rtlight->diffusescale;
1667 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1669 // 3/2 3D combine path (Geforce3, Radeon 8500)
1672 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1674 // 1/2/2 3D combine path (original Radeon)
1677 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1679 // 2/2 3D combine path (original Radeon)
1682 else if (r_textureunits.integer >= 4)
1684 // 4/2 2D combine path (Geforce3, Radeon 8500)
1689 // 2/2/2 2D combine path (any dot3 card)
1692 VectorScale(lightcolorbase, colorscale, color2);
1693 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1696 if (specularscale && glosstexture != r_texture_black)
1698 //if (gl_support_blendsquare)
1700 colorscale = specularscale;
1701 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1703 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1707 VectorScale(lightcolorbase, colorscale, color2);
1708 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1715 // TODO: add direct pants/shirt rendering
1716 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1717 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1718 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1719 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1720 if (r_shadow_rtlight->ambientscale)
1722 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
1723 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1726 if (r_shadow_rtlight->diffusescale)
1728 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
1729 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1735 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1736 memset(&m, 0, sizeof(m));
1737 m.pointer_vertex = vertex3f;
1739 GL_LockArrays(firstvertex, numvertices);
1740 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1741 GL_LockArrays(0, 0);
1745 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1747 // GLSL shader path (GFFX5200, Radeon 9500)
1748 R_Mesh_VertexPointer(vertex3f);
1749 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1750 R_Mesh_TexCoordPointer(1, 3, svector3f);
1751 R_Mesh_TexCoordPointer(2, 3, tvector3f);
1752 R_Mesh_TexCoordPointer(3, 3, normal3f);
1753 R_Mesh_TexBind(0, R_GetTexture(bumptexture));
1754 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1755 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1756 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1758 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1760 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1761 GL_LockArrays(firstvertex, numvertices);
1762 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1764 c_rt_lighttris += numtriangles;
1765 // TODO: add direct pants/shirt rendering
1766 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1768 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1769 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1770 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1772 c_rt_lighttris += numtriangles;
1774 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1776 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1777 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1778 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1780 c_rt_lighttris += numtriangles;
1782 GL_LockArrays(0, 0);
1784 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
1786 // TODO: add direct pants/shirt rendering
1787 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1788 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
1789 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1790 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
1791 if (r_shadow_rtlight->ambientscale)
1794 colorscale = r_shadow_rtlight->ambientscale;
1795 // colorscale accounts for how much we multiply the brightness
1798 // mult is how many times the final pass of the lighting will be
1799 // performed to get more brightness than otherwise possible.
1801 // Limit mult to 64 for sanity sake.
1802 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1804 // 3 3D combine path (Geforce3, Radeon 8500)
1805 memset(&m, 0, sizeof(m));
1806 m.pointer_vertex = vertex3f;
1807 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1809 m.pointer_texcoord3f[0] = vertex3f;
1810 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1812 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1813 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1815 m.tex[1] = R_GetTexture(basetexture);
1816 m.pointer_texcoord[1] = texcoord2f;
1817 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1819 m.pointer_texcoord3f[2] = vertex3f;
1820 m.texmatrix[2] = r_shadow_entitytolight;
1822 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1823 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1825 GL_BlendFunc(GL_ONE, GL_ONE);
1827 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1829 // 2 3D combine path (Geforce3, original Radeon)
1830 memset(&m, 0, sizeof(m));
1831 m.pointer_vertex = vertex3f;
1832 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1834 m.pointer_texcoord3f[0] = vertex3f;
1835 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1837 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1838 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1840 m.tex[1] = R_GetTexture(basetexture);
1841 m.pointer_texcoord[1] = texcoord2f;
1842 GL_BlendFunc(GL_ONE, GL_ONE);
1844 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1846 // 4 2D combine path (Geforce3, Radeon 8500)
1847 memset(&m, 0, sizeof(m));
1848 m.pointer_vertex = vertex3f;
1849 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1851 m.pointer_texcoord3f[0] = vertex3f;
1852 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1854 m.pointer_texcoord[0] = varray_texcoord2f[0];
1855 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1857 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1859 m.pointer_texcoord3f[1] = vertex3f;
1860 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1862 m.pointer_texcoord[1] = varray_texcoord2f[1];
1863 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1865 m.tex[2] = R_GetTexture(basetexture);
1866 m.pointer_texcoord[2] = texcoord2f;
1867 if (r_shadow_lightcubemap != r_texture_whitecube)
1869 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1871 m.pointer_texcoord3f[3] = vertex3f;
1872 m.texmatrix[3] = r_shadow_entitytolight;
1874 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1875 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1878 GL_BlendFunc(GL_ONE, GL_ONE);
1880 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1882 // 3 2D combine path (Geforce3, original Radeon)
1883 memset(&m, 0, sizeof(m));
1884 m.pointer_vertex = vertex3f;
1885 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1887 m.pointer_texcoord3f[0] = vertex3f;
1888 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1890 m.pointer_texcoord[0] = varray_texcoord2f[0];
1891 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1893 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1895 m.pointer_texcoord3f[1] = vertex3f;
1896 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1898 m.pointer_texcoord[1] = varray_texcoord2f[1];
1899 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1901 m.tex[2] = R_GetTexture(basetexture);
1902 m.pointer_texcoord[2] = texcoord2f;
1903 GL_BlendFunc(GL_ONE, GL_ONE);
1907 // 2/2/2 2D combine path (any dot3 card)
1908 memset(&m, 0, sizeof(m));
1909 m.pointer_vertex = vertex3f;
1910 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1912 m.pointer_texcoord3f[0] = vertex3f;
1913 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1915 m.pointer_texcoord[0] = varray_texcoord2f[0];
1916 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1918 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1920 m.pointer_texcoord3f[1] = vertex3f;
1921 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1923 m.pointer_texcoord[1] = varray_texcoord2f[1];
1924 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
1927 GL_ColorMask(0,0,0,1);
1928 GL_BlendFunc(GL_ONE, GL_ZERO);
1929 GL_LockArrays(firstvertex, numvertices);
1930 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1931 GL_LockArrays(0, 0);
1933 c_rt_lighttris += numtriangles;
1935 memset(&m, 0, sizeof(m));
1936 m.pointer_vertex = vertex3f;
1937 m.tex[0] = R_GetTexture(basetexture);
1938 m.pointer_texcoord[0] = texcoord2f;
1939 if (r_shadow_lightcubemap != r_texture_whitecube)
1941 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1943 m.pointer_texcoord3f[1] = vertex3f;
1944 m.texmatrix[1] = r_shadow_entitytolight;
1946 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1947 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
1950 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1952 // this final code is shared
1954 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1955 VectorScale(lightcolorbase, colorscale, color2);
1956 GL_LockArrays(firstvertex, numvertices);
1957 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1959 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1960 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1962 c_rt_lighttris += numtriangles;
1964 GL_LockArrays(0, 0);
1966 if (r_shadow_rtlight->diffusescale)
1969 colorscale = r_shadow_rtlight->diffusescale;
1970 // colorscale accounts for how much we multiply the brightness
1973 // mult is how many times the final pass of the lighting will be
1974 // performed to get more brightness than otherwise possible.
1976 // Limit mult to 64 for sanity sake.
1977 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1979 // 3/2 3D combine path (Geforce3, Radeon 8500)
1980 memset(&m, 0, sizeof(m));
1981 m.pointer_vertex = vertex3f;
1982 m.tex[0] = R_GetTexture(bumptexture);
1983 m.texcombinergb[0] = GL_REPLACE;
1984 m.pointer_texcoord[0] = texcoord2f;
1985 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1986 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1987 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1988 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);
1989 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1991 m.pointer_texcoord3f[2] = vertex3f;
1992 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1994 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1995 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
1998 GL_ColorMask(0,0,0,1);
1999 GL_BlendFunc(GL_ONE, GL_ZERO);
2000 GL_LockArrays(firstvertex, numvertices);
2001 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2002 GL_LockArrays(0, 0);
2004 c_rt_lighttris += numtriangles;
2006 memset(&m, 0, sizeof(m));
2007 m.pointer_vertex = vertex3f;
2008 m.tex[0] = R_GetTexture(basetexture);
2009 m.pointer_texcoord[0] = texcoord2f;
2010 if (r_shadow_lightcubemap != r_texture_whitecube)
2012 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2014 m.pointer_texcoord3f[1] = vertex3f;
2015 m.texmatrix[1] = r_shadow_entitytolight;
2017 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2018 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2021 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2023 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
2025 // 1/2/2 3D combine path (original Radeon)
2026 memset(&m, 0, sizeof(m));
2027 m.pointer_vertex = vertex3f;
2028 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2030 m.pointer_texcoord3f[0] = vertex3f;
2031 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2033 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2034 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2037 GL_ColorMask(0,0,0,1);
2038 GL_BlendFunc(GL_ONE, GL_ZERO);
2039 GL_LockArrays(firstvertex, numvertices);
2040 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2041 GL_LockArrays(0, 0);
2043 c_rt_lighttris += numtriangles;
2045 memset(&m, 0, sizeof(m));
2046 m.pointer_vertex = vertex3f;
2047 m.tex[0] = R_GetTexture(bumptexture);
2048 m.texcombinergb[0] = GL_REPLACE;
2049 m.pointer_texcoord[0] = texcoord2f;
2050 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2051 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2052 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2053 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);
2055 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2056 GL_LockArrays(firstvertex, numvertices);
2057 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2058 GL_LockArrays(0, 0);
2060 c_rt_lighttris += numtriangles;
2062 memset(&m, 0, sizeof(m));
2063 m.pointer_vertex = vertex3f;
2064 m.tex[0] = R_GetTexture(basetexture);
2065 m.pointer_texcoord[0] = texcoord2f;
2066 if (r_shadow_lightcubemap != r_texture_whitecube)
2068 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2070 m.pointer_texcoord3f[1] = vertex3f;
2071 m.texmatrix[1] = r_shadow_entitytolight;
2073 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2074 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2077 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2079 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2081 // 2/2 3D combine path (original Radeon)
2082 memset(&m, 0, sizeof(m));
2083 m.pointer_vertex = vertex3f;
2084 m.tex[0] = R_GetTexture(bumptexture);
2085 m.texcombinergb[0] = GL_REPLACE;
2086 m.pointer_texcoord[0] = texcoord2f;
2087 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2088 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2089 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2090 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);
2092 GL_ColorMask(0,0,0,1);
2093 GL_BlendFunc(GL_ONE, GL_ZERO);
2094 GL_LockArrays(firstvertex, numvertices);
2095 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2096 GL_LockArrays(0, 0);
2098 c_rt_lighttris += numtriangles;
2100 memset(&m, 0, sizeof(m));
2101 m.pointer_vertex = vertex3f;
2102 m.tex[0] = R_GetTexture(basetexture);
2103 m.pointer_texcoord[0] = texcoord2f;
2104 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2106 m.pointer_texcoord3f[1] = vertex3f;
2107 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2109 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2110 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2112 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2114 else if (r_textureunits.integer >= 4)
2116 // 4/2 2D combine path (Geforce3, Radeon 8500)
2117 memset(&m, 0, sizeof(m));
2118 m.pointer_vertex = vertex3f;
2119 m.tex[0] = R_GetTexture(bumptexture);
2120 m.texcombinergb[0] = GL_REPLACE;
2121 m.pointer_texcoord[0] = texcoord2f;
2122 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2123 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2124 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2125 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);
2126 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2128 m.pointer_texcoord3f[2] = vertex3f;
2129 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2131 m.pointer_texcoord[2] = varray_texcoord2f[2];
2132 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2134 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2136 m.pointer_texcoord3f[3] = vertex3f;
2137 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2139 m.pointer_texcoord[3] = varray_texcoord2f[3];
2140 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2143 GL_ColorMask(0,0,0,1);
2144 GL_BlendFunc(GL_ONE, GL_ZERO);
2145 GL_LockArrays(firstvertex, numvertices);
2146 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2147 GL_LockArrays(0, 0);
2149 c_rt_lighttris += numtriangles;
2151 memset(&m, 0, sizeof(m));
2152 m.pointer_vertex = vertex3f;
2153 m.tex[0] = R_GetTexture(basetexture);
2154 m.pointer_texcoord[0] = texcoord2f;
2155 if (r_shadow_lightcubemap != r_texture_whitecube)
2157 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2159 m.pointer_texcoord3f[1] = vertex3f;
2160 m.texmatrix[1] = r_shadow_entitytolight;
2162 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2163 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2166 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2170 // 2/2/2 2D combine path (any dot3 card)
2171 memset(&m, 0, sizeof(m));
2172 m.pointer_vertex = vertex3f;
2173 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2175 m.pointer_texcoord3f[0] = vertex3f;
2176 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2178 m.pointer_texcoord[0] = varray_texcoord2f[0];
2179 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2181 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2183 m.pointer_texcoord3f[1] = vertex3f;
2184 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2186 m.pointer_texcoord[1] = varray_texcoord2f[1];
2187 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2190 GL_ColorMask(0,0,0,1);
2191 GL_BlendFunc(GL_ONE, GL_ZERO);
2192 GL_LockArrays(firstvertex, numvertices);
2193 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2194 GL_LockArrays(0, 0);
2196 c_rt_lighttris += numtriangles;
2198 memset(&m, 0, sizeof(m));
2199 m.pointer_vertex = vertex3f;
2200 m.tex[0] = R_GetTexture(bumptexture);
2201 m.texcombinergb[0] = GL_REPLACE;
2202 m.pointer_texcoord[0] = texcoord2f;
2203 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2204 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2205 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2206 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);
2208 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2209 GL_LockArrays(firstvertex, numvertices);
2210 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2211 GL_LockArrays(0, 0);
2213 c_rt_lighttris += numtriangles;
2215 memset(&m, 0, sizeof(m));
2216 m.pointer_vertex = vertex3f;
2217 m.tex[0] = R_GetTexture(basetexture);
2218 m.pointer_texcoord[0] = texcoord2f;
2219 if (r_shadow_lightcubemap != r_texture_whitecube)
2221 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2223 m.pointer_texcoord3f[1] = vertex3f;
2224 m.texmatrix[1] = r_shadow_entitytolight;
2226 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2227 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2230 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2232 // this final code is shared
2234 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2235 VectorScale(lightcolorbase, colorscale, color2);
2236 GL_LockArrays(firstvertex, numvertices);
2237 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2239 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2240 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2242 c_rt_lighttris += numtriangles;
2244 GL_LockArrays(0, 0);
2246 if (specularscale && glosstexture != r_texture_black)
2248 // FIXME: detect blendsquare!
2249 //if (gl_support_blendsquare)
2251 colorscale = specularscale;
2253 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2255 // 2/0/0/1/2 3D combine blendsquare path
2256 memset(&m, 0, sizeof(m));
2257 m.pointer_vertex = vertex3f;
2258 m.tex[0] = R_GetTexture(bumptexture);
2259 m.pointer_texcoord[0] = texcoord2f;
2260 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2261 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2262 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2263 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);
2265 GL_ColorMask(0,0,0,1);
2266 // this squares the result
2267 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2268 GL_LockArrays(firstvertex, numvertices);
2269 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2270 GL_LockArrays(0, 0);
2272 c_rt_lighttris += numtriangles;
2274 memset(&m, 0, sizeof(m));
2275 m.pointer_vertex = vertex3f;
2277 GL_LockArrays(firstvertex, numvertices);
2278 // square alpha in framebuffer a few times to make it shiny
2279 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2280 // these comments are a test run through this math for intensity 0.5
2281 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2282 // 0.25 * 0.25 = 0.0625 (this is another pass)
2283 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2284 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2286 c_rt_lighttris += numtriangles;
2287 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2289 c_rt_lighttris += numtriangles;
2290 GL_LockArrays(0, 0);
2292 memset(&m, 0, sizeof(m));
2293 m.pointer_vertex = vertex3f;
2294 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2296 m.pointer_texcoord3f[0] = vertex3f;
2297 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2299 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2300 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2303 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2304 GL_LockArrays(firstvertex, numvertices);
2305 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2306 GL_LockArrays(0, 0);
2308 c_rt_lighttris += numtriangles;
2310 memset(&m, 0, sizeof(m));
2311 m.pointer_vertex = vertex3f;
2312 m.tex[0] = R_GetTexture(glosstexture);
2313 m.pointer_texcoord[0] = texcoord2f;
2314 if (r_shadow_lightcubemap != r_texture_whitecube)
2316 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2318 m.pointer_texcoord3f[1] = vertex3f;
2319 m.texmatrix[1] = r_shadow_entitytolight;
2321 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2322 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2325 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2327 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2329 // 2/0/0/2 3D combine blendsquare path
2330 memset(&m, 0, sizeof(m));
2331 m.pointer_vertex = vertex3f;
2332 m.tex[0] = R_GetTexture(bumptexture);
2333 m.pointer_texcoord[0] = texcoord2f;
2334 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2335 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2336 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2337 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);
2339 GL_ColorMask(0,0,0,1);
2340 // this squares the result
2341 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2342 GL_LockArrays(firstvertex, numvertices);
2343 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2344 GL_LockArrays(0, 0);
2346 c_rt_lighttris += numtriangles;
2348 memset(&m, 0, sizeof(m));
2349 m.pointer_vertex = vertex3f;
2351 GL_LockArrays(firstvertex, numvertices);
2352 // square alpha in framebuffer a few times to make it shiny
2353 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2354 // these comments are a test run through this math for intensity 0.5
2355 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2356 // 0.25 * 0.25 = 0.0625 (this is another pass)
2357 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2358 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2360 c_rt_lighttris += numtriangles;
2361 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2363 c_rt_lighttris += numtriangles;
2364 GL_LockArrays(0, 0);
2366 memset(&m, 0, sizeof(m));
2367 m.pointer_vertex = vertex3f;
2368 m.tex[0] = R_GetTexture(glosstexture);
2369 m.pointer_texcoord[0] = texcoord2f;
2370 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2372 m.pointer_texcoord3f[1] = vertex3f;
2373 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2375 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2376 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2378 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2382 // 2/0/0/2/2 2D combine blendsquare path
2383 memset(&m, 0, sizeof(m));
2384 m.pointer_vertex = vertex3f;
2385 m.tex[0] = R_GetTexture(bumptexture);
2386 m.pointer_texcoord[0] = texcoord2f;
2387 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2388 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2389 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2390 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);
2392 GL_ColorMask(0,0,0,1);
2393 // this squares the result
2394 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2395 GL_LockArrays(firstvertex, numvertices);
2396 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2397 GL_LockArrays(0, 0);
2399 c_rt_lighttris += numtriangles;
2401 memset(&m, 0, sizeof(m));
2402 m.pointer_vertex = vertex3f;
2404 GL_LockArrays(firstvertex, numvertices);
2405 // square alpha in framebuffer a few times to make it shiny
2406 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2407 // these comments are a test run through this math for intensity 0.5
2408 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2409 // 0.25 * 0.25 = 0.0625 (this is another pass)
2410 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2411 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2413 c_rt_lighttris += numtriangles;
2414 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2416 c_rt_lighttris += numtriangles;
2417 GL_LockArrays(0, 0);
2419 memset(&m, 0, sizeof(m));
2420 m.pointer_vertex = vertex3f;
2421 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2423 m.pointer_texcoord3f[0] = vertex3f;
2424 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2426 m.pointer_texcoord[0] = varray_texcoord2f[0];
2427 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2429 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2431 m.pointer_texcoord3f[1] = vertex3f;
2432 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2434 m.pointer_texcoord[1] = varray_texcoord2f[1];
2435 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2438 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2439 GL_LockArrays(firstvertex, numvertices);
2440 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2441 GL_LockArrays(0, 0);
2443 c_rt_lighttris += numtriangles;
2445 memset(&m, 0, sizeof(m));
2446 m.pointer_vertex = vertex3f;
2447 m.tex[0] = R_GetTexture(glosstexture);
2448 m.pointer_texcoord[0] = texcoord2f;
2449 if (r_shadow_lightcubemap != r_texture_whitecube)
2451 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2453 m.pointer_texcoord3f[1] = vertex3f;
2454 m.texmatrix[1] = r_shadow_entitytolight;
2456 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2457 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
2460 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2463 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2464 VectorScale(lightcolorbase, colorscale, color2);
2465 GL_LockArrays(firstvertex, numvertices);
2466 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2468 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2469 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2471 c_rt_lighttris += numtriangles;
2473 GL_LockArrays(0, 0);
2477 else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
2479 // TODO: add direct pants/shirt rendering
2480 if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2481 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
2482 if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2483 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
2484 if (r_shadow_rtlight->ambientscale)
2486 GL_BlendFunc(GL_ONE, GL_ONE);
2487 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
2488 memset(&m, 0, sizeof(m));
2489 m.pointer_vertex = vertex3f;
2490 m.tex[0] = R_GetTexture(basetexture);
2491 m.pointer_texcoord[0] = texcoord2f;
2492 if (r_textureunits.integer >= 2)
2495 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2497 m.pointer_texcoord3f[1] = vertex3f;
2498 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2500 m.pointer_texcoord[1] = varray_texcoord2f[1];
2501 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2503 if (r_textureunits.integer >= 3)
2505 // Geforce3/Radeon class but not using dot3
2506 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2508 m.pointer_texcoord3f[2] = vertex3f;
2509 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2511 m.pointer_texcoord[2] = varray_texcoord2f[2];
2512 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2516 if (r_textureunits.integer >= 3)
2517 m.pointer_color = NULL;
2519 m.pointer_color = varray_color4f;
2521 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2523 color[0] = bound(0, color2[0], 1);
2524 color[1] = bound(0, color2[1], 1);
2525 color[2] = bound(0, color2[2], 1);
2526 if (r_textureunits.integer >= 3)
2527 GL_Color(color[0], color[1], color[2], 1);
2528 else if (r_textureunits.integer >= 2)
2529 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2531 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
2532 GL_LockArrays(firstvertex, numvertices);
2533 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2534 GL_LockArrays(0, 0);
2536 c_rt_lighttris += numtriangles;
2539 if (r_shadow_rtlight->diffusescale)
2541 GL_BlendFunc(GL_ONE, GL_ONE);
2542 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
2543 memset(&m, 0, sizeof(m));
2544 m.pointer_vertex = vertex3f;
2545 m.pointer_color = varray_color4f;
2546 m.tex[0] = R_GetTexture(basetexture);
2547 m.pointer_texcoord[0] = texcoord2f;
2548 if (r_textureunits.integer >= 2)
2551 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2553 m.pointer_texcoord3f[1] = vertex3f;
2554 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2556 m.pointer_texcoord[1] = varray_texcoord2f[1];
2557 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
2559 if (r_textureunits.integer >= 3)
2561 // Geforce3/Radeon class but not using dot3
2562 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2564 m.pointer_texcoord3f[2] = vertex3f;
2565 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2567 m.pointer_texcoord[2] = varray_texcoord2f[2];
2568 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
2573 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2575 color[0] = bound(0, color2[0], 1);
2576 color[1] = bound(0, color2[1], 1);
2577 color[2] = bound(0, color2[2], 1);
2578 if (r_textureunits.integer >= 3)
2579 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2580 else if (r_textureunits.integer >= 2)
2581 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2583 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
2584 GL_LockArrays(firstvertex, numvertices);
2585 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2586 GL_LockArrays(0, 0);
2588 c_rt_lighttris += numtriangles;
2594 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2598 R_RTLight_Uncompile(rtlight);
2599 memset(rtlight, 0, sizeof(*rtlight));
2601 VectorCopy(light->origin, rtlight->shadoworigin);
2602 VectorCopy(light->color, rtlight->color);
2603 rtlight->radius = light->radius;
2604 //rtlight->cullradius = rtlight->radius;
2605 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2606 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2607 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2608 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2609 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2610 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2611 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2612 rtlight->cubemapname[0] = 0;
2613 if (light->cubemapname[0])
2614 strcpy(rtlight->cubemapname, light->cubemapname);
2615 else if (light->cubemapnum > 0)
2616 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2617 rtlight->shadow = light->shadow;
2618 rtlight->corona = light->corona;
2619 rtlight->style = light->style;
2620 rtlight->isstatic = isstatic;
2621 rtlight->coronasizescale = light->coronasizescale;
2622 rtlight->ambientscale = light->ambientscale;
2623 rtlight->diffusescale = light->diffusescale;
2624 rtlight->specularscale = light->specularscale;
2625 rtlight->flags = light->flags;
2626 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2627 // ConcatScale won't work here because this needs to scale rotate and
2628 // translate, not just rotate
2629 scale = 1.0f / rtlight->radius;
2630 for (k = 0;k < 3;k++)
2631 for (j = 0;j < 4;j++)
2632 rtlight->matrix_worldtolight.m[k][j] *= scale;
2634 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2635 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2636 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2637 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2640 // compiles rtlight geometry
2641 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2642 void R_RTLight_Compile(rtlight_t *rtlight)
2644 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2645 entity_render_t *ent = r_refdef.worldentity;
2646 model_t *model = r_refdef.worldmodel;
2649 // compile the light
2650 rtlight->compiled = true;
2651 rtlight->static_numleafs = 0;
2652 rtlight->static_numleafpvsbytes = 0;
2653 rtlight->static_leaflist = NULL;
2654 rtlight->static_leafpvs = NULL;
2655 rtlight->static_numsurfaces = 0;
2656 rtlight->static_surfacelist = NULL;
2657 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2658 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2659 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2660 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2661 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2662 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2664 if (model && model->GetLightInfo)
2666 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2667 r_shadow_compilingrtlight = rtlight;
2668 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2669 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);
2670 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2671 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2672 rtlight->static_numleafs = numleafs;
2673 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2674 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2675 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2676 rtlight->static_numsurfaces = numsurfaces;
2677 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2679 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2680 if (numleafpvsbytes)
2681 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2683 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2684 if (model->DrawShadowVolume && rtlight->shadow)
2686 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2687 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2688 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2690 if (model->DrawLight)
2692 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2693 model->DrawLight(ent, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
2694 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2696 // switch back to rendering when DrawShadowVolume or DrawLight is called
2697 r_shadow_compilingrtlight = NULL;
2701 // use smallest available cullradius - box radius or light radius
2702 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2703 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2707 if (rtlight->static_meshchain_shadow)
2710 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2713 shadowtris += mesh->numtriangles;
2719 if (rtlight->static_meshchain_light)
2722 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2725 lighttris += mesh->numtriangles;
2729 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);
2732 void R_RTLight_Uncompile(rtlight_t *rtlight)
2734 if (rtlight->compiled)
2736 if (rtlight->static_meshchain_shadow)
2737 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2738 rtlight->static_meshchain_shadow = NULL;
2739 if (rtlight->static_meshchain_light)
2740 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2741 rtlight->static_meshchain_light = NULL;
2742 // these allocations are grouped
2743 if (rtlight->static_leaflist)
2744 Mem_Free(rtlight->static_leaflist);
2745 rtlight->static_numleafs = 0;
2746 rtlight->static_numleafpvsbytes = 0;
2747 rtlight->static_leaflist = NULL;
2748 rtlight->static_leafpvs = NULL;
2749 rtlight->static_numsurfaces = 0;
2750 rtlight->static_surfacelist = NULL;
2751 rtlight->compiled = false;
2755 void R_Shadow_UncompileWorldLights(void)
2758 for (light = r_shadow_worldlightchain;light;light = light->next)
2759 R_RTLight_Uncompile(&light->rtlight);
2762 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2764 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2765 vec_t relativeshadowradius;
2766 if (ent == r_refdef.worldentity)
2768 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2771 R_Mesh_Matrix(&ent->matrix);
2772 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2774 R_Mesh_VertexPointer(mesh->vertex3f);
2775 GL_LockArrays(0, mesh->numverts);
2776 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2778 // decrement stencil if backface is behind depthbuffer
2779 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2780 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2781 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2782 c_rtcached_shadowmeshes++;
2783 c_rtcached_shadowtris += mesh->numtriangles;
2784 // increment stencil if frontface is behind depthbuffer
2785 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2786 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2788 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2789 c_rtcached_shadowmeshes++;
2790 c_rtcached_shadowtris += mesh->numtriangles;
2791 GL_LockArrays(0, 0);
2794 else if (numsurfaces)
2796 R_Mesh_Matrix(&ent->matrix);
2797 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2802 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2803 relativeshadowradius = rtlight->radius / ent->scale;
2804 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2805 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2806 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2807 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2808 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2809 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2810 R_Mesh_Matrix(&ent->matrix);
2811 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2815 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2818 // set up properties for rendering light onto this entity
2819 r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2820 r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2821 r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2822 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2823 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2824 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2825 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2826 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2827 R_Mesh_Matrix(&ent->matrix);
2828 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2830 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2831 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2832 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2833 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2835 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2838 if (ent == r_refdef.worldentity)
2840 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2842 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2843 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);
2846 ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2849 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2852 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2857 int numleafs, numsurfaces;
2858 int *leaflist, *surfacelist;
2860 int numlightentities;
2861 int numshadowentities;
2862 entity_render_t *lightentities[MAX_EDICTS];
2863 entity_render_t *shadowentities[MAX_EDICTS];
2865 // skip lights that don't light (corona only lights)
2866 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2869 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2870 VectorScale(rtlight->color, f, lightcolor);
2871 if (VectorLength2(lightcolor) < 0.01)
2874 if (rtlight->selected)
2876 f = 2 + sin(realtime * M_PI * 4.0);
2877 VectorScale(lightcolor, f, lightcolor);
2881 // loading is done before visibility checks because loading should happen
2882 // all at once at the start of a level, not when it stalls gameplay.
2883 // (especially important to benchmarks)
2885 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2886 R_RTLight_Compile(rtlight);
2888 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2890 // if the light box is offscreen, skip it
2891 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2894 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2896 // compiled light, world available and can receive realtime lighting
2897 // retrieve leaf information
2898 numleafs = rtlight->static_numleafs;
2899 leaflist = rtlight->static_leaflist;
2900 leafpvs = rtlight->static_leafpvs;
2901 numsurfaces = rtlight->static_numsurfaces;
2902 surfacelist = rtlight->static_surfacelist;
2904 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2906 // dynamic light, world available and can receive realtime lighting
2907 // calculate lit surfaces and leafs
2908 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2909 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);
2910 leaflist = r_shadow_buffer_leaflist;
2911 leafpvs = r_shadow_buffer_leafpvs;
2912 surfacelist = r_shadow_buffer_surfacelist;
2913 // if the reduced leaf bounds are offscreen, skip it
2914 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2926 // check if light is illuminating any visible leafs
2929 for (i = 0;i < numleafs;i++)
2930 if (r_worldleafvisible[leaflist[i]])
2935 // set up a scissor rectangle for this light
2936 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2939 numlightentities = 0;
2941 lightentities[numlightentities++] = r_refdef.worldentity;
2942 numshadowentities = 0;
2944 shadowentities[numshadowentities++] = r_refdef.worldentity;
2945 if (r_drawentities.integer)
2947 for (i = 0;i < r_refdef.numentities;i++)
2949 entity_render_t *ent = r_refdef.entities[i];
2950 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2952 && !(ent->flags & RENDER_TRANSPARENT)
2953 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2955 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2956 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2957 shadowentities[numshadowentities++] = ent;
2958 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2959 lightentities[numlightentities++] = ent;
2964 // return if there's nothing at all to light
2965 if (!numlightentities)
2968 R_Shadow_Stage_ActiveLight(rtlight);
2972 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2975 R_Shadow_Stage_StencilShadowVolumes();
2976 for (i = 0;i < numshadowentities;i++)
2977 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2980 if (numlightentities && !visible)
2982 R_Shadow_Stage_Lighting(usestencil);
2983 for (i = 0;i < numlightentities;i++)
2984 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2987 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2989 R_Shadow_Stage_VisibleShadowVolumes();
2990 for (i = 0;i < numshadowentities;i++)
2991 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2994 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2996 R_Shadow_Stage_VisibleLighting(usestencil);
2997 for (i = 0;i < numlightentities;i++)
2998 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
3002 void R_ShadowVolumeLighting(qboolean visible)
3007 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3008 R_Shadow_EditLights_Reload_f();
3010 R_Shadow_Stage_Begin();
3012 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3013 if (r_shadow_debuglight.integer >= 0)
3015 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3016 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3017 R_DrawRTLight(&light->rtlight, visible);
3020 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3021 if (light->flags & flag)
3022 R_DrawRTLight(&light->rtlight, visible);
3024 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
3025 R_DrawRTLight(&light->rtlight, visible);
3027 R_Shadow_Stage_End();
3030 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3031 typedef struct suffixinfo_s
3034 qboolean flipx, flipy, flipdiagonal;
3037 static suffixinfo_t suffix[3][6] =
3040 {"px", false, false, false},
3041 {"nx", false, false, false},
3042 {"py", false, false, false},
3043 {"ny", false, false, false},
3044 {"pz", false, false, false},
3045 {"nz", false, false, false}
3048 {"posx", false, false, false},
3049 {"negx", false, false, false},
3050 {"posy", false, false, false},
3051 {"negy", false, false, false},
3052 {"posz", false, false, false},
3053 {"negz", false, false, false}
3056 {"rt", true, false, true},
3057 {"lf", false, true, true},
3058 {"ft", true, true, false},
3059 {"bk", false, false, false},
3060 {"up", true, false, true},
3061 {"dn", true, false, true}
3065 static int componentorder[4] = {0, 1, 2, 3};
3067 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3069 int i, j, cubemapsize;
3070 qbyte *cubemappixels, *image_rgba;
3071 rtexture_t *cubemaptexture;
3073 // must start 0 so the first loadimagepixels has no requested width/height
3075 cubemappixels = NULL;
3076 cubemaptexture = NULL;
3077 // keep trying different suffix groups (posx, px, rt) until one loads
3078 for (j = 0;j < 3 && !cubemappixels;j++)
3080 // load the 6 images in the suffix group
3081 for (i = 0;i < 6;i++)
3083 // generate an image name based on the base and and suffix
3084 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3086 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3088 // an image loaded, make sure width and height are equal
3089 if (image_width == image_height)
3091 // if this is the first image to load successfully, allocate the cubemap memory
3092 if (!cubemappixels && image_width >= 1)
3094 cubemapsize = image_width;
3095 // note this clears to black, so unavailable sides are black
3096 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3098 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3100 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);
3103 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3105 Mem_Free(image_rgba);
3109 // if a cubemap loaded, upload it
3112 if (!r_shadow_filters_texturepool)
3113 r_shadow_filters_texturepool = R_AllocTexturePool();
3114 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3115 Mem_Free(cubemappixels);
3119 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3120 for (j = 0;j < 3;j++)
3121 for (i = 0;i < 6;i++)
3122 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3123 Con_Print(" and was unable to find any of them.\n");
3125 return cubemaptexture;
3128 rtexture_t *R_Shadow_Cubemap(const char *basename)
3131 for (i = 0;i < numcubemaps;i++)
3132 if (!strcasecmp(cubemaps[i].basename, basename))
3133 return cubemaps[i].texture;
3134 if (i >= MAX_CUBEMAPS)
3135 return r_texture_whitecube;
3137 strcpy(cubemaps[i].basename, basename);
3138 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3139 return cubemaps[i].texture;
3142 void R_Shadow_FreeCubemaps(void)
3145 R_FreeTexturePool(&r_shadow_filters_texturepool);
3148 dlight_t *R_Shadow_NewWorldLight(void)
3151 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3152 light->next = r_shadow_worldlightchain;
3153 r_shadow_worldlightchain = light;
3157 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)
3159 VectorCopy(origin, light->origin);
3160 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3161 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3162 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3163 light->color[0] = max(color[0], 0);
3164 light->color[1] = max(color[1], 0);
3165 light->color[2] = max(color[2], 0);
3166 light->radius = max(radius, 0);
3167 light->style = style;
3168 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3170 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3173 light->shadow = shadowenable;
3174 light->corona = corona;
3177 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3178 light->coronasizescale = coronasizescale;
3179 light->ambientscale = ambientscale;
3180 light->diffusescale = diffusescale;
3181 light->specularscale = specularscale;
3182 light->flags = flags;
3183 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3185 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3188 void R_Shadow_FreeWorldLight(dlight_t *light)
3190 dlight_t **lightpointer;
3191 R_RTLight_Uncompile(&light->rtlight);
3192 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3193 if (*lightpointer != light)
3194 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3195 *lightpointer = light->next;
3199 void R_Shadow_ClearWorldLights(void)
3201 while (r_shadow_worldlightchain)
3202 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3203 r_shadow_selectedlight = NULL;
3204 R_Shadow_FreeCubemaps();
3207 void R_Shadow_SelectLight(dlight_t *light)
3209 if (r_shadow_selectedlight)
3210 r_shadow_selectedlight->selected = false;
3211 r_shadow_selectedlight = light;
3212 if (r_shadow_selectedlight)
3213 r_shadow_selectedlight->selected = true;
3216 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3218 float scale = r_editlights_cursorgrid.value * 0.5f;
3219 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);
3222 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3225 const dlight_t *light;
3228 if (light->selected)
3229 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3232 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);
3235 void R_Shadow_DrawLightSprites(void)
3241 for (i = 0;i < 5;i++)
3243 lighttextures[i] = NULL;
3244 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3245 lighttextures[i] = pic->tex;
3248 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3249 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3250 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3253 void R_Shadow_SelectLightInView(void)
3255 float bestrating, rating, temp[3];
3256 dlight_t *best, *light;
3259 for (light = r_shadow_worldlightchain;light;light = light->next)
3261 VectorSubtract(light->origin, r_vieworigin, temp);
3262 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3265 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3266 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3268 bestrating = rating;
3273 R_Shadow_SelectLight(best);
3276 void R_Shadow_LoadWorldLights(void)
3278 int n, a, style, shadow, flags;
3279 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3280 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3281 if (r_refdef.worldmodel == NULL)
3283 Con_Print("No map loaded.\n");
3286 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3287 strlcat (name, ".rtlights", sizeof (name));
3288 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3298 for (;COM_Parse(t, true) && strcmp(
3299 if (COM_Parse(t, true))
3301 if (com_token[0] == '!')
3304 origin[0] = atof(com_token+1);
3307 origin[0] = atof(com_token);
3312 while (*s && *s != '\n' && *s != '\r')
3318 // check for modifier flags
3325 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);
3328 flags = LIGHTFLAG_REALTIMEMODE;
3336 coronasizescale = 0.25f;
3338 VectorClear(angles);
3341 if (a < 9 || !strcmp(cubemapname, "\"\""))
3343 // remove quotes on cubemapname
3344 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3346 cubemapname[strlen(cubemapname)-1] = 0;
3347 strcpy(cubemapname, cubemapname + 1);
3351 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);
3354 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3355 radius *= r_editlights_rtlightssizescale.value;
3356 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3364 Con_Printf("invalid rtlights file \"%s\"\n", name);
3365 Mem_Free(lightsstring);
3369 void R_Shadow_SaveWorldLights(void)
3372 int bufchars, bufmaxchars;
3374 char name[MAX_QPATH];
3376 if (!r_shadow_worldlightchain)
3378 if (r_refdef.worldmodel == NULL)
3380 Con_Print("No map loaded.\n");
3383 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3384 strlcat (name, ".rtlights", sizeof (name));
3385 bufchars = bufmaxchars = 0;
3387 for (light = r_shadow_worldlightchain;light;light = light->next)
3389 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3390 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3391 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3392 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3394 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
3395 if (bufchars + (int) strlen(line) > bufmaxchars)
3397 bufmaxchars = bufchars + strlen(line) + 2048;
3399 buf = Mem_Alloc(tempmempool, bufmaxchars);
3403 memcpy(buf, oldbuf, bufchars);
3409 memcpy(buf + bufchars, line, strlen(line));
3410 bufchars += strlen(line);
3414 FS_WriteFile(name, buf, bufchars);
3419 void R_Shadow_LoadLightsFile(void)
3422 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3423 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3424 if (r_refdef.worldmodel == NULL)
3426 Con_Print("No map loaded.\n");
3429 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3430 strlcat (name, ".lights", sizeof (name));
3431 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3439 while (*s && *s != '\n' && *s != '\r')
3445 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);
3449 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);
3452 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3453 radius = bound(15, radius, 4096);
3454 VectorScale(color, (2.0f / (8388608.0f)), color);
3455 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3463 Con_Printf("invalid lights file \"%s\"\n", name);
3464 Mem_Free(lightsstring);
3468 // tyrlite/hmap2 light types in the delay field
3469 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3471 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3473 int entnum, style, islight, skin, pflags, effects, type, n;
3476 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3477 char key[256], value[1024];
3479 if (r_refdef.worldmodel == NULL)
3481 Con_Print("No map loaded.\n");
3484 // try to load a .ent file first
3485 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3486 strlcat (key, ".ent", sizeof (key));
3487 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true);
3488 // and if that is not found, fall back to the bsp file entity string
3490 data = r_refdef.worldmodel->brush.entities;
3493 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3495 type = LIGHTTYPE_MINUSX;
3496 origin[0] = origin[1] = origin[2] = 0;
3497 originhack[0] = originhack[1] = originhack[2] = 0;
3498 angles[0] = angles[1] = angles[2] = 0;
3499 color[0] = color[1] = color[2] = 1;
3500 light[0] = light[1] = light[2] = 1;light[3] = 300;
3501 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3511 if (!COM_ParseToken(&data, false))
3513 if (com_token[0] == '}')
3514 break; // end of entity
3515 if (com_token[0] == '_')
3516 strcpy(key, com_token + 1);
3518 strcpy(key, com_token);
3519 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3520 key[strlen(key)-1] = 0;
3521 if (!COM_ParseToken(&data, false))
3523 strcpy(value, com_token);
3525 // now that we have the key pair worked out...
3526 if (!strcmp("light", key))
3528 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3532 light[0] = vec[0] * (1.0f / 256.0f);
3533 light[1] = vec[0] * (1.0f / 256.0f);
3534 light[2] = vec[0] * (1.0f / 256.0f);
3540 light[0] = vec[0] * (1.0f / 255.0f);
3541 light[1] = vec[1] * (1.0f / 255.0f);
3542 light[2] = vec[2] * (1.0f / 255.0f);
3546 else if (!strcmp("delay", key))
3548 else if (!strcmp("origin", key))
3549 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3550 else if (!strcmp("angle", key))
3551 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3552 else if (!strcmp("angles", key))
3553 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3554 else if (!strcmp("color", key))
3555 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3556 else if (!strcmp("wait", key))
3557 fadescale = atof(value);
3558 else if (!strcmp("classname", key))
3560 if (!strncmp(value, "light", 5))
3563 if (!strcmp(value, "light_fluoro"))
3568 overridecolor[0] = 1;
3569 overridecolor[1] = 1;
3570 overridecolor[2] = 1;
3572 if (!strcmp(value, "light_fluorospark"))
3577 overridecolor[0] = 1;
3578 overridecolor[1] = 1;
3579 overridecolor[2] = 1;
3581 if (!strcmp(value, "light_globe"))
3586 overridecolor[0] = 1;
3587 overridecolor[1] = 0.8;
3588 overridecolor[2] = 0.4;
3590 if (!strcmp(value, "light_flame_large_yellow"))
3595 overridecolor[0] = 1;
3596 overridecolor[1] = 0.5;
3597 overridecolor[2] = 0.1;
3599 if (!strcmp(value, "light_flame_small_yellow"))
3604 overridecolor[0] = 1;
3605 overridecolor[1] = 0.5;
3606 overridecolor[2] = 0.1;
3608 if (!strcmp(value, "light_torch_small_white"))
3613 overridecolor[0] = 1;
3614 overridecolor[1] = 0.5;
3615 overridecolor[2] = 0.1;
3617 if (!strcmp(value, "light_torch_small_walltorch"))
3622 overridecolor[0] = 1;
3623 overridecolor[1] = 0.5;
3624 overridecolor[2] = 0.1;
3628 else if (!strcmp("style", key))
3629 style = atoi(value);
3630 else if (r_refdef.worldmodel->type == mod_brushq3)
3632 if (!strcmp("scale", key))
3633 lightscale = atof(value);
3634 if (!strcmp("fade", key))
3635 fadescale = atof(value);
3637 else if (!strcmp("skin", key))
3638 skin = (int)atof(value);
3639 else if (!strcmp("pflags", key))
3640 pflags = (int)atof(value);
3641 else if (!strcmp("effects", key))
3642 effects = (int)atof(value);
3646 if (lightscale <= 0)
3650 if (color[0] == color[1] && color[0] == color[2])
3652 color[0] *= overridecolor[0];
3653 color[1] *= overridecolor[1];
3654 color[2] *= overridecolor[2];
3656 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3657 color[0] = color[0] * light[0];
3658 color[1] = color[1] * light[1];
3659 color[2] = color[2] * light[2];
3662 case LIGHTTYPE_MINUSX:
3664 case LIGHTTYPE_RECIPX:
3666 VectorScale(color, (1.0f / 16.0f), color);
3668 case LIGHTTYPE_RECIPXX:
3670 VectorScale(color, (1.0f / 16.0f), color);
3673 case LIGHTTYPE_NONE:
3677 case LIGHTTYPE_MINUSXX:
3680 VectorAdd(origin, originhack, origin);
3682 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);
3685 Mem_Free(entfiledata);
3689 void R_Shadow_SetCursorLocationForView(void)
3692 vec3_t dest, endpos;
3694 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3695 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3696 if (trace.fraction < 1)
3698 dist = trace.fraction * r_editlights_cursordistance.value;
3699 push = r_editlights_cursorpushback.value;
3703 VectorMA(trace.endpos, push, r_viewforward, endpos);
3704 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3706 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3707 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3708 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3711 void R_Shadow_UpdateWorldLightSelection(void)
3713 if (r_editlights.integer)
3715 R_Shadow_SetCursorLocationForView();
3716 R_Shadow_SelectLightInView();
3717 R_Shadow_DrawLightSprites();
3720 R_Shadow_SelectLight(NULL);
3723 void R_Shadow_EditLights_Clear_f(void)
3725 R_Shadow_ClearWorldLights();
3728 void R_Shadow_EditLights_Reload_f(void)
3730 if (!r_refdef.worldmodel)
3732 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3733 R_Shadow_ClearWorldLights();
3734 R_Shadow_LoadWorldLights();
3735 if (r_shadow_worldlightchain == NULL)
3737 R_Shadow_LoadLightsFile();
3738 if (r_shadow_worldlightchain == NULL)
3739 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3743 void R_Shadow_EditLights_Save_f(void)
3745 if (!r_refdef.worldmodel)
3747 R_Shadow_SaveWorldLights();
3750 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3752 R_Shadow_ClearWorldLights();
3753 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3756 void R_Shadow_EditLights_ImportLightsFile_f(void)
3758 R_Shadow_ClearWorldLights();
3759 R_Shadow_LoadLightsFile();
3762 void R_Shadow_EditLights_Spawn_f(void)
3765 if (!r_editlights.integer)
3767 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3770 if (Cmd_Argc() != 1)
3772 Con_Print("r_editlights_spawn does not take parameters\n");
3775 color[0] = color[1] = color[2] = 1;
3776 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3779 void R_Shadow_EditLights_Edit_f(void)
3781 vec3_t origin, angles, color;
3782 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3783 int style, shadows, flags, normalmode, realtimemode;
3784 char cubemapname[1024];
3785 if (!r_editlights.integer)
3787 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3790 if (!r_shadow_selectedlight)
3792 Con_Print("No selected light.\n");
3795 VectorCopy(r_shadow_selectedlight->origin, origin);
3796 VectorCopy(r_shadow_selectedlight->angles, angles);
3797 VectorCopy(r_shadow_selectedlight->color, color);
3798 radius = r_shadow_selectedlight->radius;
3799 style = r_shadow_selectedlight->style;
3800 if (r_shadow_selectedlight->cubemapname)
3801 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3804 shadows = r_shadow_selectedlight->shadow;
3805 corona = r_shadow_selectedlight->corona;
3806 coronasizescale = r_shadow_selectedlight->coronasizescale;
3807 ambientscale = r_shadow_selectedlight->ambientscale;
3808 diffusescale = r_shadow_selectedlight->diffusescale;
3809 specularscale = r_shadow_selectedlight->specularscale;
3810 flags = r_shadow_selectedlight->flags;
3811 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3812 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3813 if (!strcmp(Cmd_Argv(1), "origin"))
3815 if (Cmd_Argc() != 5)
3817 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3820 origin[0] = atof(Cmd_Argv(2));
3821 origin[1] = atof(Cmd_Argv(3));
3822 origin[2] = atof(Cmd_Argv(4));
3824 else if (!strcmp(Cmd_Argv(1), "originx"))
3826 if (Cmd_Argc() != 3)
3828 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3831 origin[0] = atof(Cmd_Argv(2));
3833 else if (!strcmp(Cmd_Argv(1), "originy"))
3835 if (Cmd_Argc() != 3)
3837 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3840 origin[1] = atof(Cmd_Argv(2));
3842 else if (!strcmp(Cmd_Argv(1), "originz"))
3844 if (Cmd_Argc() != 3)
3846 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3849 origin[2] = atof(Cmd_Argv(2));
3851 else if (!strcmp(Cmd_Argv(1), "move"))
3853 if (Cmd_Argc() != 5)
3855 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3858 origin[0] += atof(Cmd_Argv(2));
3859 origin[1] += atof(Cmd_Argv(3));
3860 origin[2] += atof(Cmd_Argv(4));
3862 else if (!strcmp(Cmd_Argv(1), "movex"))
3864 if (Cmd_Argc() != 3)
3866 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3869 origin[0] += atof(Cmd_Argv(2));
3871 else if (!strcmp(Cmd_Argv(1), "movey"))
3873 if (Cmd_Argc() != 3)
3875 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3878 origin[1] += atof(Cmd_Argv(2));
3880 else if (!strcmp(Cmd_Argv(1), "movez"))
3882 if (Cmd_Argc() != 3)
3884 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3887 origin[2] += atof(Cmd_Argv(2));
3889 else if (!strcmp(Cmd_Argv(1), "angles"))
3891 if (Cmd_Argc() != 5)
3893 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3896 angles[0] = atof(Cmd_Argv(2));
3897 angles[1] = atof(Cmd_Argv(3));
3898 angles[2] = atof(Cmd_Argv(4));
3900 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3902 if (Cmd_Argc() != 3)
3904 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3907 angles[0] = atof(Cmd_Argv(2));
3909 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3911 if (Cmd_Argc() != 3)
3913 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3916 angles[1] = atof(Cmd_Argv(2));
3918 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3920 if (Cmd_Argc() != 3)
3922 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3925 angles[2] = atof(Cmd_Argv(2));
3927 else if (!strcmp(Cmd_Argv(1), "color"))
3929 if (Cmd_Argc() != 5)
3931 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3934 color[0] = atof(Cmd_Argv(2));
3935 color[1] = atof(Cmd_Argv(3));
3936 color[2] = atof(Cmd_Argv(4));
3938 else if (!strcmp(Cmd_Argv(1), "radius"))
3940 if (Cmd_Argc() != 3)
3942 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3945 radius = atof(Cmd_Argv(2));
3947 else if (!strcmp(Cmd_Argv(1), "style"))
3949 if (Cmd_Argc() != 3)
3951 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3954 style = atoi(Cmd_Argv(2));
3956 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3960 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3963 if (Cmd_Argc() == 3)
3964 strcpy(cubemapname, Cmd_Argv(2));
3968 else if (!strcmp(Cmd_Argv(1), "shadows"))
3970 if (Cmd_Argc() != 3)
3972 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3975 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3977 else if (!strcmp(Cmd_Argv(1), "corona"))
3979 if (Cmd_Argc() != 3)
3981 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3984 corona = atof(Cmd_Argv(2));
3986 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3988 if (Cmd_Argc() != 3)
3990 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3993 coronasizescale = atof(Cmd_Argv(2));
3995 else if (!strcmp(Cmd_Argv(1), "ambient"))
3997 if (Cmd_Argc() != 3)
3999 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4002 ambientscale = atof(Cmd_Argv(2));
4004 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4006 if (Cmd_Argc() != 3)
4008 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4011 diffusescale = atof(Cmd_Argv(2));
4013 else if (!strcmp(Cmd_Argv(1), "specular"))
4015 if (Cmd_Argc() != 3)
4017 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4020 specularscale = atof(Cmd_Argv(2));
4022 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4024 if (Cmd_Argc() != 3)
4026 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4029 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4031 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4033 if (Cmd_Argc() != 3)
4035 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4038 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4042 Con_Print("usage: r_editlights_edit [property] [value]\n");
4043 Con_Print("Selected light's properties:\n");
4044 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4045 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4046 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4047 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4048 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4049 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4050 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4051 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4052 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4053 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4054 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4055 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4056 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4057 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4060 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4061 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4064 void R_Shadow_EditLights_EditAll_f(void)
4068 if (!r_editlights.integer)
4070 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4074 for (light = r_shadow_worldlightchain;light;light = light->next)
4076 R_Shadow_SelectLight(light);
4077 R_Shadow_EditLights_Edit_f();
4081 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4083 int lightnumber, lightcount;
4087 if (!r_editlights.integer)
4093 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4094 if (light == r_shadow_selectedlight)
4095 lightnumber = lightcount;
4096 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;
4097 if (r_shadow_selectedlight == NULL)
4099 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4100 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;
4101 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;
4102 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;
4103 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4104 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4105 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4106 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;
4107 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4108 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4109 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4110 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4111 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4112 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;
4113 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;
4116 void R_Shadow_EditLights_ToggleShadow_f(void)
4118 if (!r_editlights.integer)
4120 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4123 if (!r_shadow_selectedlight)
4125 Con_Print("No selected light.\n");
4128 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);
4131 void R_Shadow_EditLights_ToggleCorona_f(void)
4133 if (!r_editlights.integer)
4135 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4138 if (!r_shadow_selectedlight)
4140 Con_Print("No selected light.\n");
4143 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);
4146 void R_Shadow_EditLights_Remove_f(void)
4148 if (!r_editlights.integer)
4150 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4153 if (!r_shadow_selectedlight)
4155 Con_Print("No selected light.\n");
4158 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4159 r_shadow_selectedlight = NULL;
4162 void R_Shadow_EditLights_Help_f(void)
4165 "Documentation on r_editlights system:\n"
4167 "r_editlights : enable/disable editing mode\n"
4168 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4169 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4170 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4171 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4172 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4173 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4174 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4176 "r_editlights_help : this help\n"
4177 "r_editlights_clear : remove all lights\n"
4178 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4179 "r_editlights_save : save to .rtlights file\n"
4180 "r_editlights_spawn : create a light with default settings\n"
4181 "r_editlights_edit command : edit selected light - more documentation below\n"
4182 "r_editlights_remove : remove selected light\n"
4183 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4184 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4185 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4187 "origin x y z : set light location\n"
4188 "originx x: set x component of light location\n"
4189 "originy y: set y component of light location\n"
4190 "originz z: set z component of light location\n"
4191 "move x y z : adjust light location\n"
4192 "movex x: adjust x component of light location\n"
4193 "movey y: adjust y component of light location\n"
4194 "movez z: adjust z component of light location\n"
4195 "angles x y z : set light angles\n"
4196 "anglesx x: set x component of light angles\n"
4197 "anglesy y: set y component of light angles\n"
4198 "anglesz z: set z component of light angles\n"
4199 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4200 "radius radius : set radius (size) of light\n"
4201 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4202 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4203 "shadows 1/0 : turn on/off shadows\n"
4204 "corona n : set corona intensity\n"
4205 "coronasize n : set corona size (0-1)\n"
4206 "ambient n : set ambient intensity (0-1)\n"
4207 "diffuse n : set diffuse intensity (0-1)\n"
4208 "specular n : set specular intensity (0-1)\n"
4209 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4210 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4211 "<nothing> : print light properties to console\n"
4215 void R_Shadow_EditLights_CopyInfo_f(void)
4217 if (!r_editlights.integer)
4219 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4222 if (!r_shadow_selectedlight)
4224 Con_Print("No selected light.\n");
4227 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4228 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4229 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4230 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4231 if (r_shadow_selectedlight->cubemapname)
4232 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4234 r_shadow_bufferlight.cubemapname[0] = 0;
4235 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4236 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4237 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4238 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4239 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4240 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4241 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4244 void R_Shadow_EditLights_PasteInfo_f(void)
4246 if (!r_editlights.integer)
4248 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4251 if (!r_shadow_selectedlight)
4253 Con_Print("No selected light.\n");
4256 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);
4259 void R_Shadow_EditLights_Init(void)
4261 Cvar_RegisterVariable(&r_editlights);
4262 Cvar_RegisterVariable(&r_editlights_cursordistance);
4263 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4264 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4265 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4266 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4267 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4268 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4269 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4270 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4271 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4272 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4273 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4274 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4275 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4276 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4277 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4278 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4279 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4280 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4281 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4282 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);