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_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
214 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
215 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
216 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
217 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
218 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
219 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
220 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
221 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
222 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "0"};
223 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
224 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
225 cvar_t r_shadow_glsl_usehalffloat = {0, "r_shadow_glsl_usehalffloat", "0"};
226 cvar_t r_shadow_glsl_surfacenormalize = {0, "r_shadow_glsl_surfacenormalize", "1"};
227 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
228 cvar_t r_editlights = {0, "r_editlights", "0"};
229 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
230 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
231 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
232 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
233 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
235 float r_shadow_attenpower, r_shadow_attenscale;
237 rtlight_t *r_shadow_compilingrtlight;
238 dlight_t *r_shadow_worldlightchain;
239 dlight_t *r_shadow_selectedlight;
240 dlight_t r_shadow_bufferlight;
241 vec3_t r_editlights_cursorlocation;
243 rtexture_t *lighttextures[5];
245 extern int con_vislines;
247 typedef struct cubemapinfo_s
254 #define MAX_CUBEMAPS 256
255 static int numcubemaps;
256 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
258 #define SHADERPERMUTATION_SPECULAR (1<<0)
259 #define SHADERPERMUTATION_FOG (1<<1)
260 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
261 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
262 #define SHADERPERMUTATION_SURFACENORMALIZE (1<<4)
263 #define SHADERPERMUTATION_GEFORCEFX (1<<5)
264 #define SHADERPERMUTATION_COUNT (1<<6)
266 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
268 void R_Shadow_UncompileWorldLights(void);
269 void R_Shadow_ClearWorldLights(void);
270 void R_Shadow_SaveWorldLights(void);
271 void R_Shadow_LoadWorldLights(void);
272 void R_Shadow_LoadLightsFile(void);
273 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
274 void R_Shadow_EditLights_Reload_f(void);
275 void R_Shadow_ValidateCvars(void);
276 static void R_Shadow_MakeTextures(void);
277 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
279 const char *builtinshader_light_vert =
280 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
281 "// written by Forest 'LordHavoc' Hale\n"
283 "uniform vec3 LightPosition;\n"
285 "varying vec2 TexCoord;\n"
286 "varying vec3 CubeVector;\n"
287 "varying vec3 LightVector;\n"
289 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
290 "uniform vec3 EyePosition;\n"
291 "varying vec3 EyeVector;\n"
294 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
298 " // copy the surface texcoord\n"
299 " TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
301 " // transform vertex position into light attenuation/cubemap space\n"
302 " // (-1 to +1 across the light box)\n"
303 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
305 " // transform unnormalized light direction into tangent space\n"
306 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
307 " // normalize it per pixel)\n"
308 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
309 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
310 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
311 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
313 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
314 " // transform unnormalized eye direction into tangent space\n"
315 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
316 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
317 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
318 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
321 " // transform vertex to camera space, using ftransform to match non-VS\n"
323 " gl_Position = ftransform();\n"
327 const char *builtinshader_light_frag =
328 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
329 "// written by Forest 'LordHavoc' Hale\n"
331 "// use half floats if available for math performance\n"
333 "#define myhalf half\n"
334 "#define myhvec2 hvec2\n"
335 "#define myhvec3 hvec3\n"
336 "#define myhvec4 hvec4\n"
338 "#define myhalf float\n"
339 "#define myhvec2 vec2\n"
340 "#define myhvec3 vec3\n"
341 "#define myhvec4 vec4\n"
344 "uniform myhvec3 LightColor;\n"
345 "#ifdef USEOFFSETMAPPING\n"
346 "uniform myhalf OffsetMapping_Scale;\n"
347 "uniform myhalf OffsetMapping_Bias;\n"
349 "#ifdef USESPECULAR\n"
350 "uniform myhalf SpecularPower;\n"
353 "uniform myhalf FogRangeRecip;\n"
355 "uniform myhalf AmbientScale;\n"
356 "uniform myhalf DiffuseScale;\n"
357 "#ifdef USESPECULAR\n"
358 "uniform myhalf SpecularScale;\n"
361 "uniform sampler2D Texture_Normal;\n"
362 "uniform sampler2D Texture_Color;\n"
363 "#ifdef USESPECULAR\n"
364 "uniform sampler2D Texture_Gloss;\n"
366 "#ifdef USECUBEFILTER\n"
367 "uniform samplerCube Texture_Cube;\n"
370 "uniform sampler2D Texture_FogMask;\n"
373 "varying vec2 TexCoord;\n"
374 "varying vec3 CubeVector;\n"
375 "varying vec3 LightVector;\n"
376 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
377 "varying vec3 EyeVector;\n"
384 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
385 " // center and sharp falloff at the edge, this is about the most efficient\n"
386 " // we can get away with as far as providing illumination.\n"
388 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
389 " // provide significant illumination, large = slow = pain.\n"
390 " myhalf colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
394 " colorscale *= texture2D(Texture_FogMask, myhvec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
397 "#ifdef USEOFFSETMAPPING\n"
398 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
399 " myhvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
400 " myhvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
401 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
402 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
403 "#define TexCoord TexCoordOffset\n"
406 " // get the surface normal\n"
407 "#ifdef SURFACENORMALIZE\n"
408 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
410 " myhvec3 surfacenormal = -1.0 + 2.0 * myhvec3(texture2D(Texture_Normal, TexCoord));\n"
413 " // calculate shading\n"
414 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
415 " myhvec3 color = myhvec3(texture2D(Texture_Color, TexCoord)) * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
416 "#ifdef USESPECULAR\n"
417 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
418 " color += myhvec3(texture2D(Texture_Gloss, TexCoord)) * (SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower));\n"
421 "#ifdef USECUBEFILTER\n"
422 " // apply light cubemap filter\n"
423 " color *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
426 " // calculate fragment color (apply light color and attenuation/fog scaling)\n"
427 " gl_FragColor = myhvec4(color * LightColor * colorscale, 1);\n"
431 void r_shadow_start(void)
434 // use half float math where available (speed gain on NVIDIA GFFX and GF6)
435 if (gl_support_half_float)
436 Cvar_SetValue("r_shadow_glsl_usehalffloat", 1);
437 // allocate vertex processing arrays
439 r_shadow_attenuation2dtexture = NULL;
440 r_shadow_attenuation3dtexture = NULL;
441 r_shadow_texturepool = NULL;
442 r_shadow_filters_texturepool = NULL;
443 R_Shadow_ValidateCvars();
444 R_Shadow_MakeTextures();
445 maxshadowelements = 0;
446 shadowelements = NULL;
454 shadowmarklist = NULL;
456 r_shadow_buffer_numleafpvsbytes = 0;
457 r_shadow_buffer_leafpvs = NULL;
458 r_shadow_buffer_leaflist = NULL;
459 r_shadow_buffer_numsurfacepvsbytes = 0;
460 r_shadow_buffer_surfacepvs = NULL;
461 r_shadow_buffer_surfacelist = NULL;
462 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
463 r_shadow_program_light[i] = 0;
464 if (gl_support_fragment_shader)
466 char *vertstring, *fragstring;
467 int vertstrings_count;
468 int fragstrings_count;
469 const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
470 const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
471 vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false);
472 fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false);
473 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
475 vertstrings_count = 0;
476 fragstrings_count = 0;
477 if (i & SHADERPERMUTATION_SPECULAR)
479 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
480 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
482 if (i & SHADERPERMUTATION_FOG)
484 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
485 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
487 if (i & SHADERPERMUTATION_CUBEFILTER)
489 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
490 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
492 if (i & SHADERPERMUTATION_OFFSETMAPPING)
494 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
495 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
497 if (i & SHADERPERMUTATION_SURFACENORMALIZE)
499 vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
500 fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
502 if (i & SHADERPERMUTATION_GEFORCEFX)
504 // if the extension does not exist, don't try to compile it
505 if (!gl_support_halffloat)
507 vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
508 fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
510 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
511 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
512 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
513 if (!r_shadow_program_light[i])
515 Con_Printf("permutation %s %s %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", i & 16 ? "surfacenormalize" : "", i & 32 ? "geforcefx" : "", "glsl/light");
518 qglUseProgramObjectARB(r_shadow_program_light[i]);
519 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
520 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
521 if (i & SHADERPERMUTATION_SPECULAR)
523 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
525 if (i & SHADERPERMUTATION_CUBEFILTER)
527 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
529 if (i & SHADERPERMUTATION_FOG)
531 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
534 qglUseProgramObjectARB(0);
536 Mem_Free(fragstring);
538 Mem_Free(vertstring);
542 void r_shadow_shutdown(void)
545 R_Shadow_UncompileWorldLights();
546 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
548 if (r_shadow_program_light[i])
550 GL_Backend_FreeProgram(r_shadow_program_light[i]);
551 r_shadow_program_light[i] = 0;
555 r_shadow_attenuation2dtexture = NULL;
556 r_shadow_attenuation3dtexture = NULL;
557 R_FreeTexturePool(&r_shadow_texturepool);
558 R_FreeTexturePool(&r_shadow_filters_texturepool);
559 maxshadowelements = 0;
561 Mem_Free(shadowelements);
562 shadowelements = NULL;
565 Mem_Free(vertexupdate);
568 Mem_Free(vertexremap);
574 Mem_Free(shadowmark);
577 Mem_Free(shadowmarklist);
578 shadowmarklist = NULL;
580 r_shadow_buffer_numleafpvsbytes = 0;
581 if (r_shadow_buffer_leafpvs)
582 Mem_Free(r_shadow_buffer_leafpvs);
583 r_shadow_buffer_leafpvs = NULL;
584 if (r_shadow_buffer_leaflist)
585 Mem_Free(r_shadow_buffer_leaflist);
586 r_shadow_buffer_leaflist = NULL;
587 r_shadow_buffer_numsurfacepvsbytes = 0;
588 if (r_shadow_buffer_surfacepvs)
589 Mem_Free(r_shadow_buffer_surfacepvs);
590 r_shadow_buffer_surfacepvs = NULL;
591 if (r_shadow_buffer_surfacelist)
592 Mem_Free(r_shadow_buffer_surfacelist);
593 r_shadow_buffer_surfacelist = NULL;
596 void r_shadow_newmap(void)
600 void R_Shadow_Help_f(void)
603 "Documentation on r_shadow system:\n"
605 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
606 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
607 "r_shadow_debuglight : render only this light number (-1 = all)\n"
608 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
609 "r_shadow_gloss2intensity : brightness of forced gloss\n"
610 "r_shadow_glossintensity : brightness of textured gloss\n"
611 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
612 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
613 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
614 "r_shadow_portallight : use portal visibility for static light precomputation\n"
615 "r_shadow_projectdistance : shadow volume projection distance\n"
616 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
617 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
618 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
619 "r_shadow_realtime_world : use high quality world lighting mode\n"
620 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
621 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
622 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
623 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
624 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
625 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
626 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
627 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
628 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
629 "r_shadow_glsl_usehalffloat : use lower quality lighting\n"
630 "r_shadow_glsl_surfacenormalize : makes bumpmapping slightly higher quality\n"
631 "r_shadow_scissor : use scissor optimization\n"
632 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
633 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
634 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
635 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
636 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
637 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
639 "r_shadow_help : this help\n"
643 void R_Shadow_Init(void)
645 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
646 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
647 Cvar_RegisterVariable(&r_shadow_debuglight);
648 Cvar_RegisterVariable(&r_shadow_gloss);
649 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
650 Cvar_RegisterVariable(&r_shadow_glossintensity);
651 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
652 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
653 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
654 Cvar_RegisterVariable(&r_shadow_portallight);
655 Cvar_RegisterVariable(&r_shadow_projectdistance);
656 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
657 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
658 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
659 Cvar_RegisterVariable(&r_shadow_realtime_world);
660 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
661 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
662 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
663 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
664 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
665 Cvar_RegisterVariable(&r_shadow_scissor);
666 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
667 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
668 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
669 Cvar_RegisterVariable(&r_shadow_texture3d);
670 Cvar_RegisterVariable(&r_shadow_visiblelighting);
671 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
672 Cvar_RegisterVariable(&r_shadow_glsl);
673 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
674 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
675 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
676 Cvar_RegisterVariable(&r_shadow_glsl_usehalffloat);
677 Cvar_RegisterVariable(&r_shadow_glsl_surfacenormalize);
678 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
679 if (gamemode == GAME_TENEBRAE)
681 Cvar_SetValue("r_shadow_gloss", 2);
682 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
684 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
685 R_Shadow_EditLights_Init();
686 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
687 r_shadow_worldlightchain = NULL;
688 maxshadowelements = 0;
689 shadowelements = NULL;
697 shadowmarklist = NULL;
699 r_shadow_buffer_numleafpvsbytes = 0;
700 r_shadow_buffer_leafpvs = NULL;
701 r_shadow_buffer_leaflist = NULL;
702 r_shadow_buffer_numsurfacepvsbytes = 0;
703 r_shadow_buffer_surfacepvs = NULL;
704 r_shadow_buffer_surfacelist = NULL;
705 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
708 matrix4x4_t matrix_attenuationxyz =
711 {0.5, 0.0, 0.0, 0.5},
712 {0.0, 0.5, 0.0, 0.5},
713 {0.0, 0.0, 0.5, 0.5},
718 matrix4x4_t matrix_attenuationz =
721 {0.0, 0.0, 0.5, 0.5},
722 {0.0, 0.0, 0.0, 0.5},
723 {0.0, 0.0, 0.0, 0.5},
728 int *R_Shadow_ResizeShadowElements(int numtris)
730 // make sure shadowelements is big enough for this volume
731 if (maxshadowelements < numtris * 24)
733 maxshadowelements = numtris * 24;
735 Mem_Free(shadowelements);
736 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
738 return shadowelements;
741 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
743 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
744 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
745 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
747 if (r_shadow_buffer_leafpvs)
748 Mem_Free(r_shadow_buffer_leafpvs);
749 if (r_shadow_buffer_leaflist)
750 Mem_Free(r_shadow_buffer_leaflist);
751 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
752 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
753 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
755 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
757 if (r_shadow_buffer_surfacepvs)
758 Mem_Free(r_shadow_buffer_surfacepvs);
759 if (r_shadow_buffer_surfacelist)
760 Mem_Free(r_shadow_buffer_surfacelist);
761 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
762 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
763 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
767 void R_Shadow_PrepareShadowMark(int numtris)
769 // make sure shadowmark is big enough for this volume
770 if (maxshadowmark < numtris)
772 maxshadowmark = numtris;
774 Mem_Free(shadowmark);
776 Mem_Free(shadowmarklist);
777 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
778 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
782 // if shadowmarkcount wrapped we clear the array and adjust accordingly
783 if (shadowmarkcount == 0)
786 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
791 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)
794 int outtriangles = 0, outvertices = 0;
798 if (maxvertexupdate < innumvertices)
800 maxvertexupdate = innumvertices;
802 Mem_Free(vertexupdate);
804 Mem_Free(vertexremap);
805 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
806 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
810 if (vertexupdatenum == 0)
813 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
814 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
817 for (i = 0;i < numshadowmarktris;i++)
818 shadowmark[shadowmarktris[i]] = shadowmarkcount;
820 for (i = 0;i < numshadowmarktris;i++)
822 element = inelement3i + shadowmarktris[i] * 3;
823 // make sure the vertices are created
824 for (j = 0;j < 3;j++)
826 if (vertexupdate[element[j]] != vertexupdatenum)
828 float ratio, direction[3];
829 vertexupdate[element[j]] = vertexupdatenum;
830 vertexremap[element[j]] = outvertices;
831 vertex = invertex3f + element[j] * 3;
832 // project one copy of the vertex to the sphere radius of the light
833 // (FIXME: would projecting it to the light box be better?)
834 VectorSubtract(vertex, projectorigin, direction);
835 ratio = projectdistance / VectorLength(direction);
836 VectorCopy(vertex, outvertex3f);
837 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
844 for (i = 0;i < numshadowmarktris;i++)
846 int remappedelement[3];
848 const int *neighbortriangle;
850 markindex = shadowmarktris[i] * 3;
851 element = inelement3i + markindex;
852 neighbortriangle = inneighbor3i + markindex;
853 // output the front and back triangles
854 outelement3i[0] = vertexremap[element[0]];
855 outelement3i[1] = vertexremap[element[1]];
856 outelement3i[2] = vertexremap[element[2]];
857 outelement3i[3] = vertexremap[element[2]] + 1;
858 outelement3i[4] = vertexremap[element[1]] + 1;
859 outelement3i[5] = vertexremap[element[0]] + 1;
863 // output the sides (facing outward from this triangle)
864 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
866 remappedelement[0] = vertexremap[element[0]];
867 remappedelement[1] = vertexremap[element[1]];
868 outelement3i[0] = remappedelement[1];
869 outelement3i[1] = remappedelement[0];
870 outelement3i[2] = remappedelement[0] + 1;
871 outelement3i[3] = remappedelement[1];
872 outelement3i[4] = remappedelement[0] + 1;
873 outelement3i[5] = remappedelement[1] + 1;
878 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
880 remappedelement[1] = vertexremap[element[1]];
881 remappedelement[2] = vertexremap[element[2]];
882 outelement3i[0] = remappedelement[2];
883 outelement3i[1] = remappedelement[1];
884 outelement3i[2] = remappedelement[1] + 1;
885 outelement3i[3] = remappedelement[2];
886 outelement3i[4] = remappedelement[1] + 1;
887 outelement3i[5] = remappedelement[2] + 1;
892 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
894 remappedelement[0] = vertexremap[element[0]];
895 remappedelement[2] = vertexremap[element[2]];
896 outelement3i[0] = remappedelement[0];
897 outelement3i[1] = remappedelement[2];
898 outelement3i[2] = remappedelement[2] + 1;
899 outelement3i[3] = remappedelement[0];
900 outelement3i[4] = remappedelement[2] + 1;
901 outelement3i[5] = remappedelement[0] + 1;
908 *outnumvertices = outvertices;
912 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)
915 if (projectdistance < 0.1)
917 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
920 if (!numverts || !nummarktris)
922 // make sure shadowelements is big enough for this volume
923 if (maxshadowelements < nummarktris * 24)
924 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
925 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
926 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
929 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)
934 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
936 tend = firsttriangle + numtris;
937 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
938 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
939 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
941 // surface box entirely inside light box, no box cull
942 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
943 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
944 shadowmarklist[numshadowmark++] = t;
948 // surface box not entirely inside light box, cull each triangle
949 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
951 v[0] = invertex3f + e[0] * 3;
952 v[1] = invertex3f + e[1] * 3;
953 v[2] = invertex3f + e[2] * 3;
954 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
955 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
956 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
957 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
958 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
959 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
960 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
961 shadowmarklist[numshadowmark++] = t;
966 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
969 if (r_shadow_compilingrtlight)
971 // if we're compiling an rtlight, capture the mesh
972 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
975 memset(&m, 0, sizeof(m));
976 m.pointer_vertex = vertex3f;
978 GL_LockArrays(0, numvertices);
979 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
981 // decrement stencil if backface is behind depthbuffer
982 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
983 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
984 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
986 c_rt_shadowtris += numtriangles;
987 // increment stencil if frontface is behind depthbuffer
988 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
989 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
991 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
993 c_rt_shadowtris += numtriangles;
997 static void R_Shadow_MakeTextures(void)
1000 float v[3], intensity;
1002 R_FreeTexturePool(&r_shadow_texturepool);
1003 r_shadow_texturepool = R_AllocTexturePool();
1004 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
1005 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
1006 #define ATTEN2DSIZE 64
1007 #define ATTEN3DSIZE 32
1008 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
1009 for (y = 0;y < ATTEN2DSIZE;y++)
1011 for (x = 0;x < ATTEN2DSIZE;x++)
1013 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1014 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1016 intensity = 1.0f - sqrt(DotProduct(v, v));
1018 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1019 d = bound(0, intensity, 255);
1020 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1021 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1022 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1023 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1026 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1027 if (r_shadow_texture3d.integer)
1029 for (z = 0;z < ATTEN3DSIZE;z++)
1031 for (y = 0;y < ATTEN3DSIZE;y++)
1033 for (x = 0;x < ATTEN3DSIZE;x++)
1035 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1036 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1037 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1038 intensity = 1.0f - sqrt(DotProduct(v, v));
1040 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1041 d = bound(0, intensity, 255);
1042 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1043 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1044 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1045 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1049 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1054 void R_Shadow_ValidateCvars(void)
1056 if (r_shadow_texture3d.integer && !gl_texture3d)
1057 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1058 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1059 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1062 // light currently being rendered
1063 rtlight_t *r_shadow_rtlight;
1064 // light filter cubemap being used by the light
1065 static rtexture_t *r_shadow_lightcubemap;
1067 // this is the location of the eye in entity space
1068 static vec3_t r_shadow_entityeyeorigin;
1069 // this is the location of the light in entity space
1070 static vec3_t r_shadow_entitylightorigin;
1071 // this transforms entity coordinates to light filter cubemap coordinates
1072 // (also often used for other purposes)
1073 static matrix4x4_t r_shadow_entitytolight;
1074 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1075 // of attenuation texturing in full 3D (Z result often ignored)
1076 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1077 // this transforms only the Z to S, and T is always 0.5
1078 static matrix4x4_t r_shadow_entitytoattenuationz;
1079 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1080 static vec3_t r_shadow_entitylightcolorbase;
1081 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormap_pantscolor * ent->alpha
1082 static vec3_t r_shadow_entitylightcolorpants;
1083 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormap_shirtcolor * ent->alpha
1084 static vec3_t r_shadow_entitylightcolorshirt;
1086 static int r_shadow_lightpermutation;
1087 static int r_shadow_lightprog;
1089 void R_Shadow_Stage_Begin(void)
1093 R_Shadow_ValidateCvars();
1095 if (!r_shadow_attenuation2dtexture
1096 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1097 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1098 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1099 R_Shadow_MakeTextures();
1101 memset(&m, 0, sizeof(m));
1102 GL_BlendFunc(GL_ONE, GL_ZERO);
1103 GL_DepthMask(false);
1106 GL_Color(0, 0, 0, 1);
1107 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1108 qglEnable(GL_CULL_FACE);
1109 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1110 r_shadowstage = R_SHADOWSTAGE_NONE;
1113 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1115 r_shadow_rtlight = rtlight;
1118 void R_Shadow_Stage_Reset(void)
1121 if (gl_support_stenciltwoside)
1122 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1123 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1125 qglUseProgramObjectARB(0);
1126 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1127 qglBegin(GL_TRIANGLES);
1131 memset(&m, 0, sizeof(m));
1135 void R_Shadow_Stage_StencilShadowVolumes(void)
1137 R_Shadow_Stage_Reset();
1138 GL_Color(1, 1, 1, 1);
1139 GL_ColorMask(0, 0, 0, 0);
1140 GL_BlendFunc(GL_ONE, GL_ZERO);
1141 GL_DepthMask(false);
1143 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1144 //if (r_shadow_shadow_polygonoffset.value != 0)
1146 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1147 // qglEnable(GL_POLYGON_OFFSET_FILL);
1150 // qglDisable(GL_POLYGON_OFFSET_FILL);
1151 qglDepthFunc(GL_LESS);
1152 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1153 qglEnable(GL_STENCIL_TEST);
1154 qglStencilFunc(GL_ALWAYS, 128, ~0);
1155 if (gl_ext_stenciltwoside.integer)
1157 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1158 qglDisable(GL_CULL_FACE);
1159 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1160 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1162 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1163 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1165 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1169 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1170 qglEnable(GL_CULL_FACE);
1172 // this is changed by every shadow render so its value here is unimportant
1173 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1175 GL_Clear(GL_STENCIL_BUFFER_BIT);
1179 void R_Shadow_Stage_Lighting(int stenciltest)
1182 R_Shadow_Stage_Reset();
1183 GL_BlendFunc(GL_ONE, GL_ONE);
1184 GL_DepthMask(false);
1186 qglPolygonOffset(0, 0);
1187 //qglDisable(GL_POLYGON_OFFSET_FILL);
1188 GL_Color(1, 1, 1, 1);
1189 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1190 qglDepthFunc(GL_EQUAL);
1191 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1192 qglEnable(GL_CULL_FACE);
1193 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1194 qglEnable(GL_STENCIL_TEST);
1196 qglDisable(GL_STENCIL_TEST);
1198 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1199 // only draw light where this geometry was already rendered AND the
1200 // stencil is 128 (values other than this mean shadow)
1201 qglStencilFunc(GL_EQUAL, 128, ~0);
1202 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1204 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1205 memset(&m, 0, sizeof(m));
1206 m.pointer_vertex = varray_vertex3f;
1207 m.pointer_texcoord[0] = varray_texcoord2f[0];
1208 m.pointer_texcoord3f[1] = varray_svector3f;
1209 m.pointer_texcoord3f[2] = varray_tvector3f;
1210 m.pointer_texcoord3f[3] = varray_normal3f;
1211 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1212 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1213 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1214 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1215 // TODO: support fog (after renderer is converted to texture fog)
1216 m.tex[4] = R_GetTexture(r_texture_white); // fog
1217 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1219 GL_BlendFunc(GL_ONE, GL_ONE);
1220 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1222 r_shadow_lightpermutation = 0;
1223 // only add a feature to the permutation if that permutation exists
1224 // (otherwise it might end up not using a shader at all, which looks
1225 // worse than using less features)
1226 if (r_shadow_rtlight->specularscale && r_shadow_gloss.integer >= 1 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1227 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1228 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1229 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1230 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1231 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1232 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1233 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1234 if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
1235 r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
1236 if (r_shadow_glsl_usehalffloat.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
1237 r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
1238 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1239 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1240 // TODO: support fog (after renderer is converted to texture fog)
1241 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1243 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1245 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1246 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1247 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1249 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1250 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1252 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1253 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1254 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1256 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1258 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1260 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1261 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1264 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1265 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1267 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1270 void R_Shadow_Stage_VisibleShadowVolumes(void)
1272 R_Shadow_Stage_Reset();
1273 GL_BlendFunc(GL_ONE, GL_ONE);
1274 GL_DepthMask(false);
1275 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1276 qglPolygonOffset(0, 0);
1277 GL_Color(0.0, 0.0125, 0.1, 1);
1278 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1279 qglDepthFunc(GL_GEQUAL);
1280 qglCullFace(GL_FRONT); // this culls back
1281 qglDisable(GL_CULL_FACE);
1282 qglDisable(GL_STENCIL_TEST);
1283 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1286 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1288 R_Shadow_Stage_Reset();
1289 GL_BlendFunc(GL_ONE, GL_ONE);
1290 GL_DepthMask(false);
1291 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1292 qglPolygonOffset(0, 0);
1293 GL_Color(0.1, 0.0125, 0, 1);
1294 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1295 qglDepthFunc(GL_EQUAL);
1296 qglCullFace(GL_FRONT); // this culls back
1297 qglEnable(GL_CULL_FACE);
1299 qglEnable(GL_STENCIL_TEST);
1301 qglDisable(GL_STENCIL_TEST);
1302 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1305 void R_Shadow_Stage_End(void)
1307 R_Shadow_Stage_Reset();
1308 R_Shadow_Stage_ActiveLight(NULL);
1309 GL_BlendFunc(GL_ONE, GL_ZERO);
1312 qglPolygonOffset(0, 0);
1313 //qglDisable(GL_POLYGON_OFFSET_FILL);
1314 GL_Color(1, 1, 1, 1);
1315 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1316 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1317 qglDepthFunc(GL_LEQUAL);
1318 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1319 qglDisable(GL_STENCIL_TEST);
1320 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1321 if (gl_support_stenciltwoside)
1322 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1324 qglStencilFunc(GL_ALWAYS, 128, ~0);
1325 r_shadowstage = R_SHADOWSTAGE_NONE;
1328 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1330 int i, ix1, iy1, ix2, iy2;
1331 float x1, y1, x2, y2;
1334 mplane_t planes[11];
1335 float vertex3f[256*3];
1337 // if view is inside the light box, just say yes it's visible
1338 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1340 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1344 // create a temporary brush describing the area the light can affect in worldspace
1345 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1346 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1347 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1348 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1349 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1350 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1351 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1352 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1353 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1354 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1355 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1357 // turn the brush into a mesh
1358 memset(&mesh, 0, sizeof(rmesh_t));
1359 mesh.maxvertices = 256;
1360 mesh.vertex3f = vertex3f;
1361 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1362 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1364 // if that mesh is empty, the light is not visible at all
1365 if (!mesh.numvertices)
1368 if (!r_shadow_scissor.integer)
1371 // if that mesh is not empty, check what area of the screen it covers
1372 x1 = y1 = x2 = y2 = 0;
1374 for (i = 0;i < mesh.numvertices;i++)
1376 VectorCopy(mesh.vertex3f + i * 3, v);
1377 GL_TransformToScreen(v, v2);
1378 //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]);
1381 if (x1 > v2[0]) x1 = v2[0];
1382 if (x2 < v2[0]) x2 = v2[0];
1383 if (y1 > v2[1]) y1 = v2[1];
1384 if (y2 < v2[1]) y2 = v2[1];
1393 // now convert the scissor rectangle to integer screen coordinates
1398 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1400 // clamp it to the screen
1401 if (ix1 < r_view_x) ix1 = r_view_x;
1402 if (iy1 < r_view_y) iy1 = r_view_y;
1403 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1404 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1406 // if it is inside out, it's not visible
1407 if (ix2 <= ix1 || iy2 <= iy1)
1410 // the light area is visible, set up the scissor rectangle
1411 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1412 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1413 //qglEnable(GL_SCISSOR_TEST);
1418 extern float *rsurface_vertex3f;
1419 extern float *rsurface_svector3f;
1420 extern float *rsurface_tvector3f;
1421 extern float *rsurface_normal3f;
1422 extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
1424 static void R_Shadow_VertexShadingWithXYZAttenuation(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1426 int numverts = surface->num_vertices;
1427 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1428 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1429 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1430 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1431 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1433 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1434 if ((dist = DotProduct(v, v)) < 1)
1437 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1438 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1439 if ((dot = DotProduct(n, v)) > 0)
1441 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1442 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
1443 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
1444 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
1448 color4f[0] = ambientcolor[0] * distintensity - reduce;
1449 color4f[1] = ambientcolor[1] * distintensity - reduce;
1450 color4f[2] = ambientcolor[2] * distintensity - reduce;
1452 color4f[0] = bound(0, color4f[0], 1);
1453 color4f[1] = bound(0, color4f[1], 1);
1454 color4f[2] = bound(0, color4f[2], 1);
1457 VectorClear(color4f);
1462 static void R_Shadow_VertexShadingWithZAttenuation(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1464 int numverts = surface->num_vertices;
1465 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1466 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1467 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1468 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1469 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1471 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1472 if ((dist = fabs(v[2])) < 1)
1474 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1475 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1476 if ((dot = DotProduct(n, v)) > 0)
1478 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1479 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
1480 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
1481 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
1485 color4f[0] = ambientcolor[0] * distintensity - reduce;
1486 color4f[1] = ambientcolor[1] * distintensity - reduce;
1487 color4f[2] = ambientcolor[2] * distintensity - reduce;
1489 color4f[0] = bound(0, color4f[0], 1);
1490 color4f[1] = bound(0, color4f[1], 1);
1491 color4f[2] = bound(0, color4f[2], 1);
1494 VectorClear(color4f);
1499 static void R_Shadow_VertexShading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1501 int numverts = surface->num_vertices;
1502 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1503 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1504 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1505 float dot, shadeintensity, v[3], n[3];
1506 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1508 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1509 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1510 if ((dot = DotProduct(n, v)) > 0)
1512 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1513 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) - reduce;
1514 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) - reduce;
1515 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) - reduce;
1516 color4f[0] = bound(0, color4f[0], 1);
1517 color4f[1] = bound(0, color4f[1], 1);
1518 color4f[2] = bound(0, color4f[2], 1);
1521 VectorClear(color4f);
1526 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1527 #define USETEXMATRIX
1529 #ifndef USETEXMATRIX
1530 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1531 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1532 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1536 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1537 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1538 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1545 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1549 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1550 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1558 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)
1562 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1564 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1565 // the cubemap normalizes this for us
1566 out3f[0] = DotProduct(svector3f, lightdir);
1567 out3f[1] = DotProduct(tvector3f, lightdir);
1568 out3f[2] = DotProduct(normal3f, lightdir);
1572 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)
1575 float lightdir[3], eyedir[3], halfdir[3];
1576 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1578 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1579 VectorNormalize(lightdir);
1580 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1581 VectorNormalize(eyedir);
1582 VectorAdd(lightdir, eyedir, halfdir);
1583 // the cubemap normalizes this for us
1584 out3f[0] = DotProduct(svector3f, halfdir);
1585 out3f[1] = DotProduct(tvector3f, halfdir);
1586 out3f[2] = DotProduct(normal3f, halfdir);
1590 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
1592 // used to display how many times a surface is lit for level design purposes
1593 int surfacelistindex;
1595 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1596 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1597 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1598 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1599 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1600 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1601 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1602 if (!doambientbase && !dodiffusebase && !doambientpants && !dodiffusepants && !doambientshirt && !dodiffuseshirt && !dospecular)
1604 GL_Color(0.1, 0.025, 0, 1);
1605 memset(&m, 0, sizeof(m));
1607 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1609 const msurface_t *surface = surfacelist[surfacelistindex];
1610 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1611 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1612 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
1613 GL_LockArrays(0, 0);
1617 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
1619 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1620 int surfacelistindex;
1621 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1622 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1623 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1624 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1625 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1626 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1627 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1628 // TODO: add direct pants/shirt rendering
1629 if (doambientpants || dodiffusepants)
1630 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
1631 if (doambientshirt || dodiffuseshirt)
1632 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
1633 if (!doambientbase && !dodiffusebase && !dospecular)
1635 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
1636 R_Mesh_TexBind(0, R_GetTexture(normalmaptexture));
1637 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1638 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1639 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1641 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1643 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1644 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1646 const msurface_t *surface = surfacelist[surfacelistindex];
1647 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1648 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1649 if (!rsurface_svector3f)
1651 rsurface_svector3f = varray_svector3f;
1652 rsurface_tvector3f = varray_tvector3f;
1653 rsurface_normal3f = varray_normal3f;
1654 Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
1656 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1657 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1658 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1659 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1660 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1661 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1663 c_rt_lighttris += surface->num_triangles;
1664 GL_LockArrays(0, 0);
1668 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
1670 // ARB path (any Geforce, any Radeon)
1671 int surfacelistindex;
1673 float color2[3], colorscale;
1675 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1676 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1677 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1678 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1679 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1680 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1681 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1682 // TODO: add direct pants/shirt rendering
1683 if (doambientpants || dodiffusepants)
1684 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
1685 if (doambientshirt || dodiffuseshirt)
1686 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
1687 if (!doambientbase && !dodiffusebase && !dospecular)
1689 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1691 const msurface_t *surface = surfacelist[surfacelistindex];
1692 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1693 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1694 if (!rsurface_svector3f)
1696 rsurface_svector3f = varray_svector3f;
1697 rsurface_tvector3f = varray_tvector3f;
1698 rsurface_normal3f = varray_normal3f;
1699 Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
1704 colorscale = r_shadow_rtlight->ambientscale;
1705 // colorscale accounts for how much we multiply the brightness
1708 // mult is how many times the final pass of the lighting will be
1709 // performed to get more brightness than otherwise possible.
1711 // Limit mult to 64 for sanity sake.
1712 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1714 // 3 3D combine path (Geforce3, Radeon 8500)
1715 memset(&m, 0, sizeof(m));
1716 m.pointer_vertex = rsurface_vertex3f;
1717 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1719 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1720 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1722 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1723 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1725 m.tex[1] = R_GetTexture(basetexture);
1726 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1727 m.texmatrix[1] = texture->currenttexmatrix;
1728 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1730 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1731 m.texmatrix[2] = r_shadow_entitytolight;
1733 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1734 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1736 GL_BlendFunc(GL_ONE, GL_ONE);
1738 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1740 // 2 3D combine path (Geforce3, original Radeon)
1741 memset(&m, 0, sizeof(m));
1742 m.pointer_vertex = rsurface_vertex3f;
1743 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1745 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1746 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1748 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1749 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1751 m.tex[1] = R_GetTexture(basetexture);
1752 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1753 m.texmatrix[1] = texture->currenttexmatrix;
1754 GL_BlendFunc(GL_ONE, GL_ONE);
1756 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1758 // 4 2D combine path (Geforce3, Radeon 8500)
1759 memset(&m, 0, sizeof(m));
1760 m.pointer_vertex = rsurface_vertex3f;
1761 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1763 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1764 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1766 m.pointer_texcoord[0] = varray_texcoord2f[0];
1767 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1769 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1771 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1772 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1774 m.pointer_texcoord[1] = varray_texcoord2f[1];
1775 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1777 m.tex[2] = R_GetTexture(basetexture);
1778 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1779 m.texmatrix[2] = texture->currenttexmatrix;
1780 if (r_shadow_lightcubemap != r_texture_whitecube)
1782 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1784 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1785 m.texmatrix[3] = r_shadow_entitytolight;
1787 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1788 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1791 GL_BlendFunc(GL_ONE, GL_ONE);
1793 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1795 // 3 2D combine path (Geforce3, original Radeon)
1796 memset(&m, 0, sizeof(m));
1797 m.pointer_vertex = rsurface_vertex3f;
1798 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1800 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1801 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1803 m.pointer_texcoord[0] = varray_texcoord2f[0];
1804 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1806 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1808 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1809 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1811 m.pointer_texcoord[1] = varray_texcoord2f[1];
1812 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1814 m.tex[2] = R_GetTexture(basetexture);
1815 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1816 m.texmatrix[2] = texture->currenttexmatrix;
1817 GL_BlendFunc(GL_ONE, GL_ONE);
1821 // 2/2/2 2D combine path (any dot3 card)
1822 memset(&m, 0, sizeof(m));
1823 m.pointer_vertex = rsurface_vertex3f;
1824 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1826 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1827 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1829 m.pointer_texcoord[0] = varray_texcoord2f[0];
1830 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1832 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1834 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1835 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1837 m.pointer_texcoord[1] = varray_texcoord2f[1];
1838 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1841 GL_ColorMask(0,0,0,1);
1842 GL_BlendFunc(GL_ONE, GL_ZERO);
1843 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1844 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1845 GL_LockArrays(0, 0);
1847 c_rt_lighttris += surface->num_triangles;
1849 memset(&m, 0, sizeof(m));
1850 m.pointer_vertex = rsurface_vertex3f;
1851 m.tex[0] = R_GetTexture(basetexture);
1852 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1853 m.texmatrix[0] = texture->currenttexmatrix;
1854 if (r_shadow_lightcubemap != r_texture_whitecube)
1856 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1858 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1859 m.texmatrix[1] = r_shadow_entitytolight;
1861 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1862 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1865 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1867 // this final code is shared
1869 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1870 VectorScale(lightcolorbase, colorscale, color2);
1871 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1872 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1874 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1875 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1877 c_rt_lighttris += surface->num_triangles;
1879 GL_LockArrays(0, 0);
1884 colorscale = r_shadow_rtlight->diffusescale;
1885 // colorscale accounts for how much we multiply the brightness
1888 // mult is how many times the final pass of the lighting will be
1889 // performed to get more brightness than otherwise possible.
1891 // Limit mult to 64 for sanity sake.
1892 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1894 // 3/2 3D combine path (Geforce3, Radeon 8500)
1895 memset(&m, 0, sizeof(m));
1896 m.pointer_vertex = rsurface_vertex3f;
1897 m.tex[0] = R_GetTexture(normalmaptexture);
1898 m.texcombinergb[0] = GL_REPLACE;
1899 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1900 m.texmatrix[0] = texture->currenttexmatrix;
1901 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1902 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1903 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1904 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1905 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1907 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1908 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1910 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1911 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1914 GL_ColorMask(0,0,0,1);
1915 GL_BlendFunc(GL_ONE, GL_ZERO);
1916 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1917 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1918 GL_LockArrays(0, 0);
1920 c_rt_lighttris += surface->num_triangles;
1922 memset(&m, 0, sizeof(m));
1923 m.pointer_vertex = rsurface_vertex3f;
1924 m.tex[0] = R_GetTexture(basetexture);
1925 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1926 m.texmatrix[0] = texture->currenttexmatrix;
1927 if (r_shadow_lightcubemap != r_texture_whitecube)
1929 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1931 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1932 m.texmatrix[1] = r_shadow_entitytolight;
1934 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1935 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1938 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1940 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1942 // 1/2/2 3D combine path (original Radeon)
1943 memset(&m, 0, sizeof(m));
1944 m.pointer_vertex = rsurface_vertex3f;
1945 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1947 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1948 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1950 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1951 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1954 GL_ColorMask(0,0,0,1);
1955 GL_BlendFunc(GL_ONE, GL_ZERO);
1956 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1957 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1958 GL_LockArrays(0, 0);
1960 c_rt_lighttris += surface->num_triangles;
1962 memset(&m, 0, sizeof(m));
1963 m.pointer_vertex = rsurface_vertex3f;
1964 m.tex[0] = R_GetTexture(normalmaptexture);
1965 m.texcombinergb[0] = GL_REPLACE;
1966 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1967 m.texmatrix[0] = texture->currenttexmatrix;
1968 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1969 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1970 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1971 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1973 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1974 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1975 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1976 GL_LockArrays(0, 0);
1978 c_rt_lighttris += surface->num_triangles;
1980 memset(&m, 0, sizeof(m));
1981 m.pointer_vertex = rsurface_vertex3f;
1982 m.tex[0] = R_GetTexture(basetexture);
1983 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1984 m.texmatrix[0] = texture->currenttexmatrix;
1985 if (r_shadow_lightcubemap != r_texture_whitecube)
1987 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1989 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1990 m.texmatrix[1] = r_shadow_entitytolight;
1992 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1993 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1996 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1998 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
2000 // 2/2 3D combine path (original Radeon)
2001 memset(&m, 0, sizeof(m));
2002 m.pointer_vertex = rsurface_vertex3f;
2003 m.tex[0] = R_GetTexture(normalmaptexture);
2004 m.texcombinergb[0] = GL_REPLACE;
2005 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2006 m.texmatrix[0] = texture->currenttexmatrix;
2007 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2008 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2009 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2010 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
2012 GL_ColorMask(0,0,0,1);
2013 GL_BlendFunc(GL_ONE, GL_ZERO);
2014 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2015 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2016 GL_LockArrays(0, 0);
2018 c_rt_lighttris += surface->num_triangles;
2020 memset(&m, 0, sizeof(m));
2021 m.pointer_vertex = rsurface_vertex3f;
2022 m.tex[0] = R_GetTexture(basetexture);
2023 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2024 m.texmatrix[0] = texture->currenttexmatrix;
2025 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2027 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2028 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2030 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2031 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2033 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2035 else if (r_textureunits.integer >= 4)
2037 // 4/2 2D combine path (Geforce3, Radeon 8500)
2038 memset(&m, 0, sizeof(m));
2039 m.pointer_vertex = rsurface_vertex3f;
2040 m.tex[0] = R_GetTexture(normalmaptexture);
2041 m.texcombinergb[0] = GL_REPLACE;
2042 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2043 m.texmatrix[0] = texture->currenttexmatrix;
2044 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2045 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2046 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2047 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
2048 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2050 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2051 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2053 m.pointer_texcoord[2] = varray_texcoord2f[2];
2054 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2056 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2058 m.pointer_texcoord3f[3] = rsurface_vertex3f;
2059 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2061 m.pointer_texcoord[3] = varray_texcoord2f[3];
2062 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2065 GL_ColorMask(0,0,0,1);
2066 GL_BlendFunc(GL_ONE, GL_ZERO);
2067 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2068 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2069 GL_LockArrays(0, 0);
2071 c_rt_lighttris += surface->num_triangles;
2073 memset(&m, 0, sizeof(m));
2074 m.pointer_vertex = rsurface_vertex3f;
2075 m.tex[0] = R_GetTexture(basetexture);
2076 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2077 m.texmatrix[0] = texture->currenttexmatrix;
2078 if (r_shadow_lightcubemap != r_texture_whitecube)
2080 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2082 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2083 m.texmatrix[1] = r_shadow_entitytolight;
2085 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2086 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2089 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2093 // 2/2/2 2D combine path (any dot3 card)
2094 memset(&m, 0, sizeof(m));
2095 m.pointer_vertex = rsurface_vertex3f;
2096 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2098 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2099 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2101 m.pointer_texcoord[0] = varray_texcoord2f[0];
2102 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2104 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2106 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2107 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2109 m.pointer_texcoord[1] = varray_texcoord2f[1];
2110 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2113 GL_ColorMask(0,0,0,1);
2114 GL_BlendFunc(GL_ONE, GL_ZERO);
2115 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2116 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2117 GL_LockArrays(0, 0);
2119 c_rt_lighttris += surface->num_triangles;
2121 memset(&m, 0, sizeof(m));
2122 m.pointer_vertex = rsurface_vertex3f;
2123 m.tex[0] = R_GetTexture(normalmaptexture);
2124 m.texcombinergb[0] = GL_REPLACE;
2125 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2126 m.texmatrix[0] = texture->currenttexmatrix;
2127 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2128 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2129 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2130 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
2132 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2133 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2134 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2135 GL_LockArrays(0, 0);
2137 c_rt_lighttris += surface->num_triangles;
2139 memset(&m, 0, sizeof(m));
2140 m.pointer_vertex = rsurface_vertex3f;
2141 m.tex[0] = R_GetTexture(basetexture);
2142 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2143 m.texmatrix[0] = texture->currenttexmatrix;
2144 if (r_shadow_lightcubemap != r_texture_whitecube)
2146 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2148 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2149 m.texmatrix[1] = r_shadow_entitytolight;
2151 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2152 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2155 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2157 // this final code is shared
2159 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2160 VectorScale(lightcolorbase, colorscale, color2);
2161 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2162 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2164 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2165 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2167 c_rt_lighttris += surface->num_triangles;
2169 GL_LockArrays(0, 0);
2173 // FIXME: detect blendsquare!
2174 //if (gl_support_blendsquare)
2176 colorscale = specularscale;
2178 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2180 // 2/0/0/1/2 3D combine blendsquare path
2181 memset(&m, 0, sizeof(m));
2182 m.pointer_vertex = rsurface_vertex3f;
2183 m.tex[0] = R_GetTexture(normalmaptexture);
2184 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2185 m.texmatrix[0] = texture->currenttexmatrix;
2186 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2187 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2188 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2189 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2191 GL_ColorMask(0,0,0,1);
2192 // this squares the result
2193 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2194 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2195 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2196 GL_LockArrays(0, 0);
2198 c_rt_lighttris += surface->num_triangles;
2200 memset(&m, 0, sizeof(m));
2201 m.pointer_vertex = rsurface_vertex3f;
2203 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2204 // square alpha in framebuffer a few times to make it shiny
2205 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2206 // these comments are a test run through this math for intensity 0.5
2207 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2208 // 0.25 * 0.25 = 0.0625 (this is another pass)
2209 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2210 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2212 c_rt_lighttris += surface->num_triangles;
2213 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2215 c_rt_lighttris += surface->num_triangles;
2216 GL_LockArrays(0, 0);
2218 memset(&m, 0, sizeof(m));
2219 m.pointer_vertex = rsurface_vertex3f;
2220 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2222 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2223 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2225 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2226 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2229 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2230 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2231 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2232 GL_LockArrays(0, 0);
2234 c_rt_lighttris += surface->num_triangles;
2236 memset(&m, 0, sizeof(m));
2237 m.pointer_vertex = rsurface_vertex3f;
2238 m.tex[0] = R_GetTexture(glosstexture);
2239 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2240 m.texmatrix[0] = texture->currenttexmatrix;
2241 if (r_shadow_lightcubemap != r_texture_whitecube)
2243 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2245 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2246 m.texmatrix[1] = r_shadow_entitytolight;
2248 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2249 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2252 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2254 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2256 // 2/0/0/2 3D combine blendsquare path
2257 memset(&m, 0, sizeof(m));
2258 m.pointer_vertex = rsurface_vertex3f;
2259 m.tex[0] = R_GetTexture(normalmaptexture);
2260 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2261 m.texmatrix[0] = texture->currenttexmatrix;
2262 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2263 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2264 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2265 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2267 GL_ColorMask(0,0,0,1);
2268 // this squares the result
2269 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2270 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2271 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2272 GL_LockArrays(0, 0);
2274 c_rt_lighttris += surface->num_triangles;
2276 memset(&m, 0, sizeof(m));
2277 m.pointer_vertex = rsurface_vertex3f;
2279 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2280 // square alpha in framebuffer a few times to make it shiny
2281 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2282 // these comments are a test run through this math for intensity 0.5
2283 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2284 // 0.25 * 0.25 = 0.0625 (this is another pass)
2285 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2286 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2288 c_rt_lighttris += surface->num_triangles;
2289 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2291 c_rt_lighttris += surface->num_triangles;
2292 GL_LockArrays(0, 0);
2294 memset(&m, 0, sizeof(m));
2295 m.pointer_vertex = rsurface_vertex3f;
2296 m.tex[0] = R_GetTexture(glosstexture);
2297 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2298 m.texmatrix[0] = texture->currenttexmatrix;
2299 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2301 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2302 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2304 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2305 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2307 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2311 // 2/0/0/2/2 2D combine blendsquare path
2312 memset(&m, 0, sizeof(m));
2313 m.pointer_vertex = rsurface_vertex3f;
2314 m.tex[0] = R_GetTexture(normalmaptexture);
2315 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2316 m.texmatrix[0] = texture->currenttexmatrix;
2317 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2318 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2319 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2320 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
2322 GL_ColorMask(0,0,0,1);
2323 // this squares the result
2324 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2325 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2326 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2327 GL_LockArrays(0, 0);
2329 c_rt_lighttris += surface->num_triangles;
2331 memset(&m, 0, sizeof(m));
2332 m.pointer_vertex = rsurface_vertex3f;
2334 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2335 // square alpha in framebuffer a few times to make it shiny
2336 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2337 // these comments are a test run through this math for intensity 0.5
2338 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2339 // 0.25 * 0.25 = 0.0625 (this is another pass)
2340 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2341 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2343 c_rt_lighttris += surface->num_triangles;
2344 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2346 c_rt_lighttris += surface->num_triangles;
2347 GL_LockArrays(0, 0);
2349 memset(&m, 0, sizeof(m));
2350 m.pointer_vertex = rsurface_vertex3f;
2351 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2353 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2354 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2356 m.pointer_texcoord[0] = varray_texcoord2f[0];
2357 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2359 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2361 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2362 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2364 m.pointer_texcoord[1] = varray_texcoord2f[1];
2365 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2368 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2369 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2370 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2371 GL_LockArrays(0, 0);
2373 c_rt_lighttris += surface->num_triangles;
2375 memset(&m, 0, sizeof(m));
2376 m.pointer_vertex = rsurface_vertex3f;
2377 m.tex[0] = R_GetTexture(glosstexture);
2378 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2379 m.texmatrix[0] = texture->currenttexmatrix;
2380 if (r_shadow_lightcubemap != r_texture_whitecube)
2382 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2384 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2385 m.texmatrix[1] = r_shadow_entitytolight;
2387 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2388 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2391 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2394 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2395 VectorScale(lightcolorbase, colorscale, color2);
2396 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2397 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2399 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2400 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2402 c_rt_lighttris += surface->num_triangles;
2404 GL_LockArrays(0, 0);
2410 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
2412 int surfacelistindex;
2414 float ambientcolor2[3], diffusecolor2[3];
2416 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
2417 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
2418 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
2419 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
2420 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
2421 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
2422 //qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
2423 // TODO: add direct pants/shirt rendering
2424 if (doambientpants || dodiffusepants)
2425 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
2426 if (doambientshirt || dodiffuseshirt)
2427 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
2428 if (!doambientbase && !dodiffusebase)
2430 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, ambientcolor2);
2431 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, diffusecolor2);
2432 GL_BlendFunc(GL_ONE, GL_ONE);
2433 memset(&m, 0, sizeof(m));
2434 m.tex[0] = R_GetTexture(basetexture);
2435 if (r_textureunits.integer >= 2)
2438 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2440 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2442 m.pointer_texcoord[1] = varray_texcoord2f[1];
2443 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2445 if (r_textureunits.integer >= 3)
2447 // Geforce3/Radeon class but not using dot3
2448 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2450 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2452 m.pointer_texcoord[2] = varray_texcoord2f[2];
2453 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2457 m.pointer_color = varray_color4f;
2459 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2461 const msurface_t *surface = surfacelist[surfacelistindex];
2462 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2463 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2464 if (!rsurface_svector3f)
2466 rsurface_svector3f = varray_svector3f;
2467 rsurface_tvector3f = varray_tvector3f;
2468 rsurface_normal3f = varray_normal3f;
2469 Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
2471 // OpenGL 1.1 path (anything)
2472 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2473 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
2474 if (r_textureunits.integer >= 2)
2478 R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
2480 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2482 if (r_textureunits.integer >= 3)
2484 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2486 R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
2488 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2492 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
2494 if (r_textureunits.integer >= 3)
2495 R_Shadow_VertexShading(surface, diffusecolor2, ambientcolor2, renders);
2496 else if (r_textureunits.integer >= 2)
2497 R_Shadow_VertexShadingWithZAttenuation(surface, diffusecolor2, ambientcolor2, renders);
2499 R_Shadow_VertexShadingWithXYZAttenuation(surface, diffusecolor2, ambientcolor2, renders);
2500 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2501 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2502 GL_LockArrays(0, 0);
2504 c_rt_lighttris += surface->num_triangles;
2509 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
2511 // FIXME: support MATERIALFLAG_NODEPTHTEST
2512 switch (r_shadowstage)
2514 case R_SHADOWSTAGE_VISIBLELIGHTING:
2515 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2517 case R_SHADOWSTAGE_LIGHT_GLSL:
2518 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2520 case R_SHADOWSTAGE_LIGHT_DOT3:
2521 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2523 case R_SHADOWSTAGE_LIGHT_VERTEX:
2524 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2527 Con_Printf("R_Shadow_RenderLighting: unknown r_shadowstage %i\n", r_shadowstage);
2532 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2536 R_RTLight_Uncompile(rtlight);
2537 memset(rtlight, 0, sizeof(*rtlight));
2539 VectorCopy(light->origin, rtlight->shadoworigin);
2540 VectorCopy(light->color, rtlight->color);
2541 rtlight->radius = light->radius;
2542 //rtlight->cullradius = rtlight->radius;
2543 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2544 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2545 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2546 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2547 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2548 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2549 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2550 rtlight->cubemapname[0] = 0;
2551 if (light->cubemapname[0])
2552 strcpy(rtlight->cubemapname, light->cubemapname);
2553 else if (light->cubemapnum > 0)
2554 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2555 rtlight->shadow = light->shadow;
2556 rtlight->corona = light->corona;
2557 rtlight->style = light->style;
2558 rtlight->isstatic = isstatic;
2559 rtlight->coronasizescale = light->coronasizescale;
2560 rtlight->ambientscale = light->ambientscale;
2561 rtlight->diffusescale = light->diffusescale;
2562 rtlight->specularscale = light->specularscale;
2563 rtlight->flags = light->flags;
2564 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2565 // ConcatScale won't work here because this needs to scale rotate and
2566 // translate, not just rotate
2567 scale = 1.0f / rtlight->radius;
2568 for (k = 0;k < 3;k++)
2569 for (j = 0;j < 4;j++)
2570 rtlight->matrix_worldtolight.m[k][j] *= scale;
2572 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2573 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2574 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2575 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2578 // compiles rtlight geometry
2579 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2580 void R_RTLight_Compile(rtlight_t *rtlight)
2582 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2583 entity_render_t *ent = r_refdef.worldentity;
2584 model_t *model = r_refdef.worldmodel;
2587 // compile the light
2588 rtlight->compiled = true;
2589 rtlight->static_numleafs = 0;
2590 rtlight->static_numleafpvsbytes = 0;
2591 rtlight->static_leaflist = NULL;
2592 rtlight->static_leafpvs = NULL;
2593 rtlight->static_numsurfaces = 0;
2594 rtlight->static_surfacelist = NULL;
2595 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2596 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2597 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2598 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2599 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2600 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2602 if (model && model->GetLightInfo)
2604 // this variable must be set for the CompileShadowVolume code
2605 r_shadow_compilingrtlight = rtlight;
2606 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2607 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);
2608 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2609 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2610 rtlight->static_numleafs = numleafs;
2611 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2612 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2613 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2614 rtlight->static_numsurfaces = numsurfaces;
2615 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2617 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2618 if (numleafpvsbytes)
2619 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2621 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2622 if (model->CompileShadowVolume && rtlight->shadow)
2623 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2624 // now we're done compiling the rtlight
2625 r_shadow_compilingrtlight = NULL;
2629 // use smallest available cullradius - box radius or light radius
2630 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2631 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2635 if (rtlight->static_meshchain_shadow)
2638 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2641 shadowtris += mesh->numtriangles;
2645 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume 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);
2648 void R_RTLight_Uncompile(rtlight_t *rtlight)
2650 if (rtlight->compiled)
2652 if (rtlight->static_meshchain_shadow)
2653 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2654 rtlight->static_meshchain_shadow = NULL;
2655 // these allocations are grouped
2656 if (rtlight->static_leaflist)
2657 Mem_Free(rtlight->static_leaflist);
2658 rtlight->static_numleafs = 0;
2659 rtlight->static_numleafpvsbytes = 0;
2660 rtlight->static_leaflist = NULL;
2661 rtlight->static_leafpvs = NULL;
2662 rtlight->static_numsurfaces = 0;
2663 rtlight->static_surfacelist = NULL;
2664 rtlight->compiled = false;
2668 void R_Shadow_UncompileWorldLights(void)
2671 for (light = r_shadow_worldlightchain;light;light = light->next)
2672 R_RTLight_Uncompile(&light->rtlight);
2675 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2677 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2678 vec_t relativeshadowradius;
2679 if (ent == r_refdef.worldentity)
2681 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2684 R_Mesh_Matrix(&ent->matrix);
2685 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2687 R_Mesh_VertexPointer(mesh->vertex3f);
2688 GL_LockArrays(0, mesh->numverts);
2689 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2691 // decrement stencil if backface is behind depthbuffer
2692 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2693 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2694 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2695 c_rtcached_shadowmeshes++;
2696 c_rtcached_shadowtris += mesh->numtriangles;
2697 // increment stencil if frontface is behind depthbuffer
2698 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2699 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2701 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2702 c_rtcached_shadowmeshes++;
2703 c_rtcached_shadowtris += mesh->numtriangles;
2704 GL_LockArrays(0, 0);
2707 else if (numsurfaces)
2709 R_Mesh_Matrix(&ent->matrix);
2710 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2715 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2716 relativeshadowradius = rtlight->radius / ent->scale;
2717 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2718 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2719 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2720 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2721 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2722 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2723 R_Mesh_Matrix(&ent->matrix);
2724 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2728 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2730 // set up properties for rendering light onto this entity
2731 r_shadow_entitylightcolorbase[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2732 r_shadow_entitylightcolorbase[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2733 r_shadow_entitylightcolorbase[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2734 r_shadow_entitylightcolorpants[0] = lightcolor[0] * ent->colormap_pantscolor[0] * ent->alpha;
2735 r_shadow_entitylightcolorpants[1] = lightcolor[1] * ent->colormap_pantscolor[1] * ent->alpha;
2736 r_shadow_entitylightcolorpants[2] = lightcolor[2] * ent->colormap_pantscolor[2] * ent->alpha;
2737 r_shadow_entitylightcolorshirt[0] = lightcolor[0] * ent->colormap_shirtcolor[0] * ent->alpha;
2738 r_shadow_entitylightcolorshirt[1] = lightcolor[1] * ent->colormap_shirtcolor[1] * ent->alpha;
2739 r_shadow_entitylightcolorshirt[2] = lightcolor[2] * ent->colormap_shirtcolor[2] * ent->alpha;
2740 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2741 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2742 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2743 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2744 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2745 R_Mesh_Matrix(&ent->matrix);
2746 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2748 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2749 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2750 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2751 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2753 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2756 if (ent == r_refdef.worldentity)
2757 ent->model->DrawLight(ent, r_shadow_entitylightcolorbase, r_shadow_entitylightcolorpants, r_shadow_entitylightcolorshirt, numsurfaces, surfacelist);
2759 ent->model->DrawLight(ent, r_shadow_entitylightcolorbase, r_shadow_entitylightcolorpants, r_shadow_entitylightcolorshirt, ent->model->nummodelsurfaces, ent->model->surfacelist);
2762 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2767 int numleafs, numsurfaces;
2768 int *leaflist, *surfacelist;
2770 int numlightentities;
2771 int numshadowentities;
2772 entity_render_t *lightentities[MAX_EDICTS];
2773 entity_render_t *shadowentities[MAX_EDICTS];
2775 // skip lights that don't light (corona only lights)
2776 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < (1.0f / 32768.0f))
2779 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2780 VectorScale(rtlight->color, f, lightcolor);
2781 if (VectorLength2(lightcolor) < (1.0f / 32768.0f))
2784 if (rtlight->selected)
2786 f = 2 + sin(realtime * M_PI * 4.0);
2787 VectorScale(lightcolor, f, lightcolor);
2791 // loading is done before visibility checks because loading should happen
2792 // all at once at the start of a level, not when it stalls gameplay.
2793 // (especially important to benchmarks)
2795 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2796 R_RTLight_Compile(rtlight);
2798 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2800 // if the light box is offscreen, skip it
2801 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2804 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2806 // compiled light, world available and can receive realtime lighting
2807 // retrieve leaf information
2808 numleafs = rtlight->static_numleafs;
2809 leaflist = rtlight->static_leaflist;
2810 leafpvs = rtlight->static_leafpvs;
2811 numsurfaces = rtlight->static_numsurfaces;
2812 surfacelist = rtlight->static_surfacelist;
2814 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2816 // dynamic light, world available and can receive realtime lighting
2817 // calculate lit surfaces and leafs
2818 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2819 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);
2820 leaflist = r_shadow_buffer_leaflist;
2821 leafpvs = r_shadow_buffer_leafpvs;
2822 surfacelist = r_shadow_buffer_surfacelist;
2823 // if the reduced leaf bounds are offscreen, skip it
2824 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2836 // check if light is illuminating any visible leafs
2839 for (i = 0;i < numleafs;i++)
2840 if (r_worldleafvisible[leaflist[i]])
2845 // set up a scissor rectangle for this light
2846 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2849 numlightentities = 0;
2851 lightentities[numlightentities++] = r_refdef.worldentity;
2852 numshadowentities = 0;
2854 shadowentities[numshadowentities++] = r_refdef.worldentity;
2855 if (r_drawentities.integer)
2857 for (i = 0;i < r_refdef.numentities;i++)
2859 entity_render_t *ent = r_refdef.entities[i];
2860 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2862 && !(ent->flags & RENDER_TRANSPARENT)
2863 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2865 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2866 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2867 shadowentities[numshadowentities++] = ent;
2868 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2869 lightentities[numlightentities++] = ent;
2874 // return if there's nothing at all to light
2875 if (!numlightentities)
2878 R_Shadow_Stage_ActiveLight(rtlight);
2882 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2885 R_Shadow_Stage_StencilShadowVolumes();
2886 for (i = 0;i < numshadowentities;i++)
2887 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2890 if (numlightentities && !visible)
2892 R_Shadow_Stage_Lighting(usestencil);
2893 for (i = 0;i < numlightentities;i++)
2894 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2897 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2899 R_Shadow_Stage_VisibleShadowVolumes();
2900 for (i = 0;i < numshadowentities;i++)
2901 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2904 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2906 R_Shadow_Stage_VisibleLighting(usestencil);
2907 for (i = 0;i < numlightentities;i++)
2908 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2912 void R_ShadowVolumeLighting(qboolean visible)
2917 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2918 R_Shadow_EditLights_Reload_f();
2920 R_Shadow_Stage_Begin();
2922 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2923 if (r_shadow_debuglight.integer >= 0)
2925 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2926 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2927 R_DrawRTLight(&light->rtlight, visible);
2930 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2931 if (light->flags & flag)
2932 R_DrawRTLight(&light->rtlight, visible);
2934 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2935 R_DrawRTLight(&light->rtlight, visible);
2937 R_Shadow_Stage_End();
2940 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2941 typedef struct suffixinfo_s
2944 qboolean flipx, flipy, flipdiagonal;
2947 static suffixinfo_t suffix[3][6] =
2950 {"px", false, false, false},
2951 {"nx", false, false, false},
2952 {"py", false, false, false},
2953 {"ny", false, false, false},
2954 {"pz", false, false, false},
2955 {"nz", false, false, false}
2958 {"posx", false, false, false},
2959 {"negx", false, false, false},
2960 {"posy", false, false, false},
2961 {"negy", false, false, false},
2962 {"posz", false, false, false},
2963 {"negz", false, false, false}
2966 {"rt", true, false, true},
2967 {"lf", false, true, true},
2968 {"ft", true, true, false},
2969 {"bk", false, false, false},
2970 {"up", true, false, true},
2971 {"dn", true, false, true}
2975 static int componentorder[4] = {0, 1, 2, 3};
2977 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2979 int i, j, cubemapsize;
2980 qbyte *cubemappixels, *image_rgba;
2981 rtexture_t *cubemaptexture;
2983 // must start 0 so the first loadimagepixels has no requested width/height
2985 cubemappixels = NULL;
2986 cubemaptexture = NULL;
2987 // keep trying different suffix groups (posx, px, rt) until one loads
2988 for (j = 0;j < 3 && !cubemappixels;j++)
2990 // load the 6 images in the suffix group
2991 for (i = 0;i < 6;i++)
2993 // generate an image name based on the base and and suffix
2994 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2996 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2998 // an image loaded, make sure width and height are equal
2999 if (image_width == image_height)
3001 // if this is the first image to load successfully, allocate the cubemap memory
3002 if (!cubemappixels && image_width >= 1)
3004 cubemapsize = image_width;
3005 // note this clears to black, so unavailable sides are black
3006 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3008 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3010 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);
3013 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3015 Mem_Free(image_rgba);
3019 // if a cubemap loaded, upload it
3022 if (!r_shadow_filters_texturepool)
3023 r_shadow_filters_texturepool = R_AllocTexturePool();
3024 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3025 Mem_Free(cubemappixels);
3029 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3030 for (j = 0;j < 3;j++)
3031 for (i = 0;i < 6;i++)
3032 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3033 Con_Print(" and was unable to find any of them.\n");
3035 return cubemaptexture;
3038 rtexture_t *R_Shadow_Cubemap(const char *basename)
3041 for (i = 0;i < numcubemaps;i++)
3042 if (!strcasecmp(cubemaps[i].basename, basename))
3043 return cubemaps[i].texture;
3044 if (i >= MAX_CUBEMAPS)
3045 return r_texture_whitecube;
3047 strcpy(cubemaps[i].basename, basename);
3048 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3049 if (!cubemaps[i].texture)
3050 cubemaps[i].texture = r_texture_whitecube;
3051 return cubemaps[i].texture;
3054 void R_Shadow_FreeCubemaps(void)
3057 R_FreeTexturePool(&r_shadow_filters_texturepool);
3060 dlight_t *R_Shadow_NewWorldLight(void)
3063 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3064 light->next = r_shadow_worldlightchain;
3065 r_shadow_worldlightchain = light;
3069 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)
3071 VectorCopy(origin, light->origin);
3072 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3073 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3074 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3075 light->color[0] = max(color[0], 0);
3076 light->color[1] = max(color[1], 0);
3077 light->color[2] = max(color[2], 0);
3078 light->radius = max(radius, 0);
3079 light->style = style;
3080 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3082 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3085 light->shadow = shadowenable;
3086 light->corona = corona;
3089 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3090 light->coronasizescale = coronasizescale;
3091 light->ambientscale = ambientscale;
3092 light->diffusescale = diffusescale;
3093 light->specularscale = specularscale;
3094 light->flags = flags;
3095 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3097 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3100 void R_Shadow_FreeWorldLight(dlight_t *light)
3102 dlight_t **lightpointer;
3103 R_RTLight_Uncompile(&light->rtlight);
3104 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3105 if (*lightpointer != light)
3106 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3107 *lightpointer = light->next;
3111 void R_Shadow_ClearWorldLights(void)
3113 while (r_shadow_worldlightchain)
3114 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3115 r_shadow_selectedlight = NULL;
3116 R_Shadow_FreeCubemaps();
3119 void R_Shadow_SelectLight(dlight_t *light)
3121 if (r_shadow_selectedlight)
3122 r_shadow_selectedlight->selected = false;
3123 r_shadow_selectedlight = light;
3124 if (r_shadow_selectedlight)
3125 r_shadow_selectedlight->selected = true;
3128 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3130 float scale = r_editlights_cursorgrid.value * 0.5f;
3131 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);
3134 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3137 const dlight_t *light;
3140 if (light->selected)
3141 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3144 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);
3147 void R_Shadow_DrawLightSprites(void)
3153 for (i = 0;i < 5;i++)
3155 lighttextures[i] = NULL;
3156 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3157 lighttextures[i] = pic->tex;
3160 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3161 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3162 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3165 void R_Shadow_SelectLightInView(void)
3167 float bestrating, rating, temp[3];
3168 dlight_t *best, *light;
3171 for (light = r_shadow_worldlightchain;light;light = light->next)
3173 VectorSubtract(light->origin, r_vieworigin, temp);
3174 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3177 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3178 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3180 bestrating = rating;
3185 R_Shadow_SelectLight(best);
3188 void R_Shadow_LoadWorldLights(void)
3190 int n, a, style, shadow, flags;
3191 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3192 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3193 if (r_refdef.worldmodel == NULL)
3195 Con_Print("No map loaded.\n");
3198 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3199 strlcat (name, ".rtlights", sizeof (name));
3200 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3210 for (;COM_Parse(t, true) && strcmp(
3211 if (COM_Parse(t, true))
3213 if (com_token[0] == '!')
3216 origin[0] = atof(com_token+1);
3219 origin[0] = atof(com_token);
3224 while (*s && *s != '\n' && *s != '\r')
3230 // check for modifier flags
3237 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);
3240 flags = LIGHTFLAG_REALTIMEMODE;
3248 coronasizescale = 0.25f;
3250 VectorClear(angles);
3253 if (a < 9 || !strcmp(cubemapname, "\"\""))
3255 // remove quotes on cubemapname
3256 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3258 cubemapname[strlen(cubemapname)-1] = 0;
3259 strcpy(cubemapname, cubemapname + 1);
3263 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);
3266 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3274 Con_Printf("invalid rtlights file \"%s\"\n", name);
3275 Mem_Free(lightsstring);
3279 void R_Shadow_SaveWorldLights(void)
3282 size_t bufchars, bufmaxchars;
3284 char name[MAX_QPATH];
3286 if (!r_shadow_worldlightchain)
3288 if (r_refdef.worldmodel == NULL)
3290 Con_Print("No map loaded.\n");
3293 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3294 strlcat (name, ".rtlights", sizeof (name));
3295 bufchars = bufmaxchars = 0;
3297 for (light = r_shadow_worldlightchain;light;light = light->next)
3299 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3300 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3301 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3302 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3304 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style);
3305 if (bufchars + strlen(line) > bufmaxchars)
3307 bufmaxchars = bufchars + strlen(line) + 2048;
3309 buf = Mem_Alloc(tempmempool, bufmaxchars);
3313 memcpy(buf, oldbuf, bufchars);
3319 memcpy(buf + bufchars, line, strlen(line));
3320 bufchars += strlen(line);
3324 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3329 void R_Shadow_LoadLightsFile(void)
3332 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3333 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3334 if (r_refdef.worldmodel == NULL)
3336 Con_Print("No map loaded.\n");
3339 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3340 strlcat (name, ".lights", sizeof (name));
3341 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3349 while (*s && *s != '\n' && *s != '\r')
3355 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);
3359 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);
3362 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3363 radius = bound(15, radius, 4096);
3364 VectorScale(color, (2.0f / (8388608.0f)), color);
3365 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3373 Con_Printf("invalid lights file \"%s\"\n", name);
3374 Mem_Free(lightsstring);
3378 // tyrlite/hmap2 light types in the delay field
3379 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3381 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3383 int entnum, style, islight, skin, pflags, effects, type, n;
3386 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3387 char key[256], value[1024];
3389 if (r_refdef.worldmodel == NULL)
3391 Con_Print("No map loaded.\n");
3394 // try to load a .ent file first
3395 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3396 strlcat (key, ".ent", sizeof (key));
3397 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true);
3398 // and if that is not found, fall back to the bsp file entity string
3400 data = r_refdef.worldmodel->brush.entities;
3403 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3405 type = LIGHTTYPE_MINUSX;
3406 origin[0] = origin[1] = origin[2] = 0;
3407 originhack[0] = originhack[1] = originhack[2] = 0;
3408 angles[0] = angles[1] = angles[2] = 0;
3409 color[0] = color[1] = color[2] = 1;
3410 light[0] = light[1] = light[2] = 1;light[3] = 300;
3411 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3421 if (!COM_ParseToken(&data, false))
3423 if (com_token[0] == '}')
3424 break; // end of entity
3425 if (com_token[0] == '_')
3426 strcpy(key, com_token + 1);
3428 strcpy(key, com_token);
3429 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3430 key[strlen(key)-1] = 0;
3431 if (!COM_ParseToken(&data, false))
3433 strcpy(value, com_token);
3435 // now that we have the key pair worked out...
3436 if (!strcmp("light", key))
3438 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3442 light[0] = vec[0] * (1.0f / 256.0f);
3443 light[1] = vec[0] * (1.0f / 256.0f);
3444 light[2] = vec[0] * (1.0f / 256.0f);
3450 light[0] = vec[0] * (1.0f / 255.0f);
3451 light[1] = vec[1] * (1.0f / 255.0f);
3452 light[2] = vec[2] * (1.0f / 255.0f);
3456 else if (!strcmp("delay", key))
3458 else if (!strcmp("origin", key))
3459 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3460 else if (!strcmp("angle", key))
3461 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3462 else if (!strcmp("angles", key))
3463 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3464 else if (!strcmp("color", key))
3465 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3466 else if (!strcmp("wait", key))
3467 fadescale = atof(value);
3468 else if (!strcmp("classname", key))
3470 if (!strncmp(value, "light", 5))
3473 if (!strcmp(value, "light_fluoro"))
3478 overridecolor[0] = 1;
3479 overridecolor[1] = 1;
3480 overridecolor[2] = 1;
3482 if (!strcmp(value, "light_fluorospark"))
3487 overridecolor[0] = 1;
3488 overridecolor[1] = 1;
3489 overridecolor[2] = 1;
3491 if (!strcmp(value, "light_globe"))
3496 overridecolor[0] = 1;
3497 overridecolor[1] = 0.8;
3498 overridecolor[2] = 0.4;
3500 if (!strcmp(value, "light_flame_large_yellow"))
3505 overridecolor[0] = 1;
3506 overridecolor[1] = 0.5;
3507 overridecolor[2] = 0.1;
3509 if (!strcmp(value, "light_flame_small_yellow"))
3514 overridecolor[0] = 1;
3515 overridecolor[1] = 0.5;
3516 overridecolor[2] = 0.1;
3518 if (!strcmp(value, "light_torch_small_white"))
3523 overridecolor[0] = 1;
3524 overridecolor[1] = 0.5;
3525 overridecolor[2] = 0.1;
3527 if (!strcmp(value, "light_torch_small_walltorch"))
3532 overridecolor[0] = 1;
3533 overridecolor[1] = 0.5;
3534 overridecolor[2] = 0.1;
3538 else if (!strcmp("style", key))
3539 style = atoi(value);
3540 else if (!strcmp("skin", key))
3541 skin = (int)atof(value);
3542 else if (!strcmp("pflags", key))
3543 pflags = (int)atof(value);
3544 else if (!strcmp("effects", key))
3545 effects = (int)atof(value);
3546 else if (r_refdef.worldmodel->type == mod_brushq3)
3548 if (!strcmp("scale", key))
3549 lightscale = atof(value);
3550 if (!strcmp("fade", key))
3551 fadescale = atof(value);
3556 if (lightscale <= 0)
3560 if (color[0] == color[1] && color[0] == color[2])
3562 color[0] *= overridecolor[0];
3563 color[1] *= overridecolor[1];
3564 color[2] *= overridecolor[2];
3566 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3567 color[0] = color[0] * light[0];
3568 color[1] = color[1] * light[1];
3569 color[2] = color[2] * light[2];
3572 case LIGHTTYPE_MINUSX:
3574 case LIGHTTYPE_RECIPX:
3576 VectorScale(color, (1.0f / 16.0f), color);
3578 case LIGHTTYPE_RECIPXX:
3580 VectorScale(color, (1.0f / 16.0f), color);
3583 case LIGHTTYPE_NONE:
3587 case LIGHTTYPE_MINUSXX:
3590 VectorAdd(origin, originhack, origin);
3592 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);
3595 Mem_Free(entfiledata);
3599 void R_Shadow_SetCursorLocationForView(void)
3602 vec3_t dest, endpos;
3604 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3605 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3606 if (trace.fraction < 1)
3608 dist = trace.fraction * r_editlights_cursordistance.value;
3609 push = r_editlights_cursorpushback.value;
3613 VectorMA(trace.endpos, push, r_viewforward, endpos);
3614 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3618 VectorClear( endpos );
3620 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3621 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3622 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3625 void R_Shadow_UpdateWorldLightSelection(void)
3627 if (r_editlights.integer)
3629 R_Shadow_SetCursorLocationForView();
3630 R_Shadow_SelectLightInView();
3631 R_Shadow_DrawLightSprites();
3634 R_Shadow_SelectLight(NULL);
3637 void R_Shadow_EditLights_Clear_f(void)
3639 R_Shadow_ClearWorldLights();
3642 void R_Shadow_EditLights_Reload_f(void)
3644 if (!r_refdef.worldmodel)
3646 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3647 R_Shadow_ClearWorldLights();
3648 R_Shadow_LoadWorldLights();
3649 if (r_shadow_worldlightchain == NULL)
3651 R_Shadow_LoadLightsFile();
3652 if (r_shadow_worldlightchain == NULL)
3653 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3657 void R_Shadow_EditLights_Save_f(void)
3659 if (!r_refdef.worldmodel)
3661 R_Shadow_SaveWorldLights();
3664 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3666 R_Shadow_ClearWorldLights();
3667 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3670 void R_Shadow_EditLights_ImportLightsFile_f(void)
3672 R_Shadow_ClearWorldLights();
3673 R_Shadow_LoadLightsFile();
3676 void R_Shadow_EditLights_Spawn_f(void)
3679 if (!r_editlights.integer)
3681 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3684 if (Cmd_Argc() != 1)
3686 Con_Print("r_editlights_spawn does not take parameters\n");
3689 color[0] = color[1] = color[2] = 1;
3690 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3693 void R_Shadow_EditLights_Edit_f(void)
3695 vec3_t origin, angles, color;
3696 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3697 int style, shadows, flags, normalmode, realtimemode;
3698 char cubemapname[1024];
3699 if (!r_editlights.integer)
3701 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3704 if (!r_shadow_selectedlight)
3706 Con_Print("No selected light.\n");
3709 VectorCopy(r_shadow_selectedlight->origin, origin);
3710 VectorCopy(r_shadow_selectedlight->angles, angles);
3711 VectorCopy(r_shadow_selectedlight->color, color);
3712 radius = r_shadow_selectedlight->radius;
3713 style = r_shadow_selectedlight->style;
3714 if (r_shadow_selectedlight->cubemapname)
3715 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3718 shadows = r_shadow_selectedlight->shadow;
3719 corona = r_shadow_selectedlight->corona;
3720 coronasizescale = r_shadow_selectedlight->coronasizescale;
3721 ambientscale = r_shadow_selectedlight->ambientscale;
3722 diffusescale = r_shadow_selectedlight->diffusescale;
3723 specularscale = r_shadow_selectedlight->specularscale;
3724 flags = r_shadow_selectedlight->flags;
3725 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3726 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3727 if (!strcmp(Cmd_Argv(1), "origin"))
3729 if (Cmd_Argc() != 5)
3731 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3734 origin[0] = atof(Cmd_Argv(2));
3735 origin[1] = atof(Cmd_Argv(3));
3736 origin[2] = atof(Cmd_Argv(4));
3738 else if (!strcmp(Cmd_Argv(1), "originx"))
3740 if (Cmd_Argc() != 3)
3742 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3745 origin[0] = atof(Cmd_Argv(2));
3747 else if (!strcmp(Cmd_Argv(1), "originy"))
3749 if (Cmd_Argc() != 3)
3751 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3754 origin[1] = atof(Cmd_Argv(2));
3756 else if (!strcmp(Cmd_Argv(1), "originz"))
3758 if (Cmd_Argc() != 3)
3760 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3763 origin[2] = atof(Cmd_Argv(2));
3765 else if (!strcmp(Cmd_Argv(1), "move"))
3767 if (Cmd_Argc() != 5)
3769 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3772 origin[0] += atof(Cmd_Argv(2));
3773 origin[1] += atof(Cmd_Argv(3));
3774 origin[2] += atof(Cmd_Argv(4));
3776 else if (!strcmp(Cmd_Argv(1), "movex"))
3778 if (Cmd_Argc() != 3)
3780 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3783 origin[0] += atof(Cmd_Argv(2));
3785 else if (!strcmp(Cmd_Argv(1), "movey"))
3787 if (Cmd_Argc() != 3)
3789 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3792 origin[1] += atof(Cmd_Argv(2));
3794 else if (!strcmp(Cmd_Argv(1), "movez"))
3796 if (Cmd_Argc() != 3)
3798 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3801 origin[2] += atof(Cmd_Argv(2));
3803 else if (!strcmp(Cmd_Argv(1), "angles"))
3805 if (Cmd_Argc() != 5)
3807 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3810 angles[0] = atof(Cmd_Argv(2));
3811 angles[1] = atof(Cmd_Argv(3));
3812 angles[2] = atof(Cmd_Argv(4));
3814 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3816 if (Cmd_Argc() != 3)
3818 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3821 angles[0] = atof(Cmd_Argv(2));
3823 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3825 if (Cmd_Argc() != 3)
3827 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3830 angles[1] = atof(Cmd_Argv(2));
3832 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3834 if (Cmd_Argc() != 3)
3836 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3839 angles[2] = atof(Cmd_Argv(2));
3841 else if (!strcmp(Cmd_Argv(1), "color"))
3843 if (Cmd_Argc() != 5)
3845 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3848 color[0] = atof(Cmd_Argv(2));
3849 color[1] = atof(Cmd_Argv(3));
3850 color[2] = atof(Cmd_Argv(4));
3852 else if (!strcmp(Cmd_Argv(1), "radius"))
3854 if (Cmd_Argc() != 3)
3856 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3859 radius = atof(Cmd_Argv(2));
3861 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3863 if (Cmd_Argc() == 3)
3865 double scale = atof(Cmd_Argv(2));
3872 if (Cmd_Argc() != 5)
3874 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3877 color[0] *= atof(Cmd_Argv(2));
3878 color[1] *= atof(Cmd_Argv(3));
3879 color[2] *= atof(Cmd_Argv(4));
3882 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3884 if (Cmd_Argc() != 3)
3886 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3889 radius *= atof(Cmd_Argv(2));
3891 else if (!strcmp(Cmd_Argv(1), "style"))
3893 if (Cmd_Argc() != 3)
3895 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3898 style = atoi(Cmd_Argv(2));
3900 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3904 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3907 if (Cmd_Argc() == 3)
3908 strcpy(cubemapname, Cmd_Argv(2));
3912 else if (!strcmp(Cmd_Argv(1), "shadows"))
3914 if (Cmd_Argc() != 3)
3916 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3919 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3921 else if (!strcmp(Cmd_Argv(1), "corona"))
3923 if (Cmd_Argc() != 3)
3925 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3928 corona = atof(Cmd_Argv(2));
3930 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3932 if (Cmd_Argc() != 3)
3934 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3937 coronasizescale = atof(Cmd_Argv(2));
3939 else if (!strcmp(Cmd_Argv(1), "ambient"))
3941 if (Cmd_Argc() != 3)
3943 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3946 ambientscale = atof(Cmd_Argv(2));
3948 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3950 if (Cmd_Argc() != 3)
3952 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3955 diffusescale = atof(Cmd_Argv(2));
3957 else if (!strcmp(Cmd_Argv(1), "specular"))
3959 if (Cmd_Argc() != 3)
3961 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3964 specularscale = atof(Cmd_Argv(2));
3966 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3968 if (Cmd_Argc() != 3)
3970 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3973 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3975 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3977 if (Cmd_Argc() != 3)
3979 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3982 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3986 Con_Print("usage: r_editlights_edit [property] [value]\n");
3987 Con_Print("Selected light's properties:\n");
3988 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3989 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3990 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3991 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3992 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3993 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3994 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3995 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3996 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3997 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3998 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3999 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4000 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4001 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4004 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4005 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4008 void R_Shadow_EditLights_EditAll_f(void)
4012 if (!r_editlights.integer)
4014 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4018 for (light = r_shadow_worldlightchain;light;light = light->next)
4020 R_Shadow_SelectLight(light);
4021 R_Shadow_EditLights_Edit_f();
4025 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4027 int lightnumber, lightcount;
4031 if (!r_editlights.integer)
4037 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4038 if (light == r_shadow_selectedlight)
4039 lightnumber = lightcount;
4040 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;
4041 if (r_shadow_selectedlight == NULL)
4043 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4044 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;
4045 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;
4046 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;
4047 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4048 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4049 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4050 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;
4051 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4052 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4053 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4054 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4055 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4056 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;
4057 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;
4060 void R_Shadow_EditLights_ToggleShadow_f(void)
4062 if (!r_editlights.integer)
4064 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4067 if (!r_shadow_selectedlight)
4069 Con_Print("No selected light.\n");
4072 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);
4075 void R_Shadow_EditLights_ToggleCorona_f(void)
4077 if (!r_editlights.integer)
4079 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4082 if (!r_shadow_selectedlight)
4084 Con_Print("No selected light.\n");
4087 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);
4090 void R_Shadow_EditLights_Remove_f(void)
4092 if (!r_editlights.integer)
4094 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4097 if (!r_shadow_selectedlight)
4099 Con_Print("No selected light.\n");
4102 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4103 r_shadow_selectedlight = NULL;
4106 void R_Shadow_EditLights_Help_f(void)
4109 "Documentation on r_editlights system:\n"
4111 "r_editlights : enable/disable editing mode\n"
4112 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4113 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4114 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4115 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4116 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4118 "r_editlights_help : this help\n"
4119 "r_editlights_clear : remove all lights\n"
4120 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4121 "r_editlights_save : save to .rtlights file\n"
4122 "r_editlights_spawn : create a light with default settings\n"
4123 "r_editlights_edit command : edit selected light - more documentation below\n"
4124 "r_editlights_remove : remove selected light\n"
4125 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4126 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4127 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4129 "origin x y z : set light location\n"
4130 "originx x: set x component of light location\n"
4131 "originy y: set y component of light location\n"
4132 "originz z: set z component of light location\n"
4133 "move x y z : adjust light location\n"
4134 "movex x: adjust x component of light location\n"
4135 "movey y: adjust y component of light location\n"
4136 "movez z: adjust z component of light location\n"
4137 "angles x y z : set light angles\n"
4138 "anglesx x: set x component of light angles\n"
4139 "anglesy y: set y component of light angles\n"
4140 "anglesz z: set z component of light angles\n"
4141 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4142 "radius radius : set radius (size) of light\n"
4143 "colorscale grey : multiply color of light (1 does nothing)\n"
4144 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4145 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4146 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4147 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4148 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4149 "shadows 1/0 : turn on/off shadows\n"
4150 "corona n : set corona intensity\n"
4151 "coronasize n : set corona size (0-1)\n"
4152 "ambient n : set ambient intensity (0-1)\n"
4153 "diffuse n : set diffuse intensity (0-1)\n"
4154 "specular n : set specular intensity (0-1)\n"
4155 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4156 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4157 "<nothing> : print light properties to console\n"
4161 void R_Shadow_EditLights_CopyInfo_f(void)
4163 if (!r_editlights.integer)
4165 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4168 if (!r_shadow_selectedlight)
4170 Con_Print("No selected light.\n");
4173 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4174 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4175 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4176 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4177 if (r_shadow_selectedlight->cubemapname)
4178 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4180 r_shadow_bufferlight.cubemapname[0] = 0;
4181 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4182 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4183 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4184 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4185 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4186 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4187 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4190 void R_Shadow_EditLights_PasteInfo_f(void)
4192 if (!r_editlights.integer)
4194 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4197 if (!r_shadow_selectedlight)
4199 Con_Print("No selected light.\n");
4202 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);
4205 void R_Shadow_EditLights_Init(void)
4207 Cvar_RegisterVariable(&r_editlights);
4208 Cvar_RegisterVariable(&r_editlights_cursordistance);
4209 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4210 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4211 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4212 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4213 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4214 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4215 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4216 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4217 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4218 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4219 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4220 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4221 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4222 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4223 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4224 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4225 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4226 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);