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 vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
505 fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
507 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
508 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
509 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
510 if (!r_shadow_program_light[i])
512 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");
515 qglUseProgramObjectARB(r_shadow_program_light[i]);
516 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
517 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
518 if (i & SHADERPERMUTATION_SPECULAR)
520 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
522 if (i & SHADERPERMUTATION_CUBEFILTER)
524 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
526 if (i & SHADERPERMUTATION_FOG)
528 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
531 qglUseProgramObjectARB(0);
533 Mem_Free(fragstring);
535 Mem_Free(vertstring);
539 void r_shadow_shutdown(void)
542 R_Shadow_UncompileWorldLights();
543 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
545 if (r_shadow_program_light[i])
547 GL_Backend_FreeProgram(r_shadow_program_light[i]);
548 r_shadow_program_light[i] = 0;
552 r_shadow_attenuation2dtexture = NULL;
553 r_shadow_attenuation3dtexture = NULL;
554 R_FreeTexturePool(&r_shadow_texturepool);
555 R_FreeTexturePool(&r_shadow_filters_texturepool);
556 maxshadowelements = 0;
558 Mem_Free(shadowelements);
559 shadowelements = NULL;
562 Mem_Free(vertexupdate);
565 Mem_Free(vertexremap);
571 Mem_Free(shadowmark);
574 Mem_Free(shadowmarklist);
575 shadowmarklist = NULL;
577 r_shadow_buffer_numleafpvsbytes = 0;
578 if (r_shadow_buffer_leafpvs)
579 Mem_Free(r_shadow_buffer_leafpvs);
580 r_shadow_buffer_leafpvs = NULL;
581 if (r_shadow_buffer_leaflist)
582 Mem_Free(r_shadow_buffer_leaflist);
583 r_shadow_buffer_leaflist = NULL;
584 r_shadow_buffer_numsurfacepvsbytes = 0;
585 if (r_shadow_buffer_surfacepvs)
586 Mem_Free(r_shadow_buffer_surfacepvs);
587 r_shadow_buffer_surfacepvs = NULL;
588 if (r_shadow_buffer_surfacelist)
589 Mem_Free(r_shadow_buffer_surfacelist);
590 r_shadow_buffer_surfacelist = NULL;
593 void r_shadow_newmap(void)
597 void R_Shadow_Help_f(void)
600 "Documentation on r_shadow system:\n"
602 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
603 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
604 "r_shadow_debuglight : render only this light number (-1 = all)\n"
605 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
606 "r_shadow_gloss2intensity : brightness of forced gloss\n"
607 "r_shadow_glossintensity : brightness of textured gloss\n"
608 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
609 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
610 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
611 "r_shadow_portallight : use portal visibility for static light precomputation\n"
612 "r_shadow_projectdistance : shadow volume projection distance\n"
613 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
614 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
615 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
616 "r_shadow_realtime_world : use high quality world lighting mode\n"
617 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
618 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
619 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
620 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
621 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
622 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
623 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
624 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
625 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
626 "r_shadow_glsl_usehalffloat : use lower quality lighting\n"
627 "r_shadow_glsl_surfacenormalize : makes bumpmapping slightly higher quality\n"
628 "r_shadow_scissor : use scissor optimization\n"
629 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
630 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
631 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
632 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
633 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
634 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
636 "r_shadow_help : this help\n"
640 void R_Shadow_Init(void)
642 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
643 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
644 Cvar_RegisterVariable(&r_shadow_debuglight);
645 Cvar_RegisterVariable(&r_shadow_gloss);
646 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
647 Cvar_RegisterVariable(&r_shadow_glossintensity);
648 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
649 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
650 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
651 Cvar_RegisterVariable(&r_shadow_portallight);
652 Cvar_RegisterVariable(&r_shadow_projectdistance);
653 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
654 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
655 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
656 Cvar_RegisterVariable(&r_shadow_realtime_world);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
660 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
661 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
662 Cvar_RegisterVariable(&r_shadow_scissor);
663 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
664 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
665 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
666 Cvar_RegisterVariable(&r_shadow_texture3d);
667 Cvar_RegisterVariable(&r_shadow_visiblelighting);
668 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
669 Cvar_RegisterVariable(&r_shadow_glsl);
670 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
671 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
672 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
673 Cvar_RegisterVariable(&r_shadow_glsl_usehalffloat);
674 Cvar_RegisterVariable(&r_shadow_glsl_surfacenormalize);
675 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
676 if (gamemode == GAME_TENEBRAE)
678 Cvar_SetValue("r_shadow_gloss", 2);
679 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
681 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
682 R_Shadow_EditLights_Init();
683 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
684 r_shadow_worldlightchain = NULL;
685 maxshadowelements = 0;
686 shadowelements = NULL;
694 shadowmarklist = NULL;
696 r_shadow_buffer_numleafpvsbytes = 0;
697 r_shadow_buffer_leafpvs = NULL;
698 r_shadow_buffer_leaflist = NULL;
699 r_shadow_buffer_numsurfacepvsbytes = 0;
700 r_shadow_buffer_surfacepvs = NULL;
701 r_shadow_buffer_surfacelist = NULL;
702 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
705 matrix4x4_t matrix_attenuationxyz =
708 {0.5, 0.0, 0.0, 0.5},
709 {0.0, 0.5, 0.0, 0.5},
710 {0.0, 0.0, 0.5, 0.5},
715 matrix4x4_t matrix_attenuationz =
718 {0.0, 0.0, 0.5, 0.5},
719 {0.0, 0.0, 0.0, 0.5},
720 {0.0, 0.0, 0.0, 0.5},
725 int *R_Shadow_ResizeShadowElements(int numtris)
727 // make sure shadowelements is big enough for this volume
728 if (maxshadowelements < numtris * 24)
730 maxshadowelements = numtris * 24;
732 Mem_Free(shadowelements);
733 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
735 return shadowelements;
738 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
740 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
741 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
742 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
744 if (r_shadow_buffer_leafpvs)
745 Mem_Free(r_shadow_buffer_leafpvs);
746 if (r_shadow_buffer_leaflist)
747 Mem_Free(r_shadow_buffer_leaflist);
748 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
749 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
750 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
752 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
754 if (r_shadow_buffer_surfacepvs)
755 Mem_Free(r_shadow_buffer_surfacepvs);
756 if (r_shadow_buffer_surfacelist)
757 Mem_Free(r_shadow_buffer_surfacelist);
758 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
759 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
760 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
764 void R_Shadow_PrepareShadowMark(int numtris)
766 // make sure shadowmark is big enough for this volume
767 if (maxshadowmark < numtris)
769 maxshadowmark = numtris;
771 Mem_Free(shadowmark);
773 Mem_Free(shadowmarklist);
774 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
775 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
779 // if shadowmarkcount wrapped we clear the array and adjust accordingly
780 if (shadowmarkcount == 0)
783 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
788 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
791 int outtriangles = 0, outvertices = 0;
795 if (maxvertexupdate < innumvertices)
797 maxvertexupdate = innumvertices;
799 Mem_Free(vertexupdate);
801 Mem_Free(vertexremap);
802 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
803 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
807 if (vertexupdatenum == 0)
810 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
811 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
814 for (i = 0;i < numshadowmarktris;i++)
815 shadowmark[shadowmarktris[i]] = shadowmarkcount;
817 for (i = 0;i < numshadowmarktris;i++)
819 element = inelement3i + shadowmarktris[i] * 3;
820 // make sure the vertices are created
821 for (j = 0;j < 3;j++)
823 if (vertexupdate[element[j]] != vertexupdatenum)
825 float ratio, direction[3];
826 vertexupdate[element[j]] = vertexupdatenum;
827 vertexremap[element[j]] = outvertices;
828 vertex = invertex3f + element[j] * 3;
829 // project one copy of the vertex to the sphere radius of the light
830 // (FIXME: would projecting it to the light box be better?)
831 VectorSubtract(vertex, projectorigin, direction);
832 ratio = projectdistance / VectorLength(direction);
833 VectorCopy(vertex, outvertex3f);
834 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
841 for (i = 0;i < numshadowmarktris;i++)
843 int remappedelement[3];
845 const int *neighbortriangle;
847 markindex = shadowmarktris[i] * 3;
848 element = inelement3i + markindex;
849 neighbortriangle = inneighbor3i + markindex;
850 // output the front and back triangles
851 outelement3i[0] = vertexremap[element[0]];
852 outelement3i[1] = vertexremap[element[1]];
853 outelement3i[2] = vertexremap[element[2]];
854 outelement3i[3] = vertexremap[element[2]] + 1;
855 outelement3i[4] = vertexremap[element[1]] + 1;
856 outelement3i[5] = vertexremap[element[0]] + 1;
860 // output the sides (facing outward from this triangle)
861 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
863 remappedelement[0] = vertexremap[element[0]];
864 remappedelement[1] = vertexremap[element[1]];
865 outelement3i[0] = remappedelement[1];
866 outelement3i[1] = remappedelement[0];
867 outelement3i[2] = remappedelement[0] + 1;
868 outelement3i[3] = remappedelement[1];
869 outelement3i[4] = remappedelement[0] + 1;
870 outelement3i[5] = remappedelement[1] + 1;
875 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
877 remappedelement[1] = vertexremap[element[1]];
878 remappedelement[2] = vertexremap[element[2]];
879 outelement3i[0] = remappedelement[2];
880 outelement3i[1] = remappedelement[1];
881 outelement3i[2] = remappedelement[1] + 1;
882 outelement3i[3] = remappedelement[2];
883 outelement3i[4] = remappedelement[1] + 1;
884 outelement3i[5] = remappedelement[2] + 1;
889 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
891 remappedelement[0] = vertexremap[element[0]];
892 remappedelement[2] = vertexremap[element[2]];
893 outelement3i[0] = remappedelement[0];
894 outelement3i[1] = remappedelement[2];
895 outelement3i[2] = remappedelement[2] + 1;
896 outelement3i[3] = remappedelement[0];
897 outelement3i[4] = remappedelement[2] + 1;
898 outelement3i[5] = remappedelement[0] + 1;
905 *outnumvertices = outvertices;
909 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
912 if (projectdistance < 0.1)
914 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
917 if (!numverts || !nummarktris)
919 // make sure shadowelements is big enough for this volume
920 if (maxshadowelements < nummarktris * 24)
921 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
922 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
923 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
926 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
931 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
933 tend = firsttriangle + numtris;
934 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
935 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
936 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
938 // surface box entirely inside light box, no box cull
939 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
940 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
941 shadowmarklist[numshadowmark++] = t;
945 // surface box not entirely inside light box, cull each triangle
946 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
948 v[0] = invertex3f + e[0] * 3;
949 v[1] = invertex3f + e[1] * 3;
950 v[2] = invertex3f + e[2] * 3;
951 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
952 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
953 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
954 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
955 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
956 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
957 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
958 shadowmarklist[numshadowmark++] = t;
963 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
966 if (r_shadow_compilingrtlight)
968 // if we're compiling an rtlight, capture the mesh
969 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
972 memset(&m, 0, sizeof(m));
973 m.pointer_vertex = vertex3f;
975 GL_LockArrays(0, numvertices);
976 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
978 // decrement stencil if backface is behind depthbuffer
979 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
980 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
981 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
983 c_rt_shadowtris += numtriangles;
984 // increment stencil if frontface is behind depthbuffer
985 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
986 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
988 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
990 c_rt_shadowtris += numtriangles;
994 static void R_Shadow_MakeTextures(void)
997 float v[3], intensity;
999 R_FreeTexturePool(&r_shadow_texturepool);
1000 r_shadow_texturepool = R_AllocTexturePool();
1001 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
1002 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
1003 #define ATTEN2DSIZE 64
1004 #define ATTEN3DSIZE 32
1005 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
1006 for (y = 0;y < ATTEN2DSIZE;y++)
1008 for (x = 0;x < ATTEN2DSIZE;x++)
1010 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1011 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1013 intensity = 1.0f - sqrt(DotProduct(v, v));
1015 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1016 d = bound(0, intensity, 255);
1017 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1018 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1019 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1020 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1023 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1024 if (r_shadow_texture3d.integer)
1026 for (z = 0;z < ATTEN3DSIZE;z++)
1028 for (y = 0;y < ATTEN3DSIZE;y++)
1030 for (x = 0;x < ATTEN3DSIZE;x++)
1032 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1033 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1034 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1035 intensity = 1.0f - sqrt(DotProduct(v, v));
1037 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1038 d = bound(0, intensity, 255);
1039 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1040 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1041 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1042 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1046 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1051 void R_Shadow_ValidateCvars(void)
1053 if (r_shadow_texture3d.integer && !gl_texture3d)
1054 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1055 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1056 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1059 // light currently being rendered
1060 rtlight_t *r_shadow_rtlight;
1061 // light filter cubemap being used by the light
1062 static rtexture_t *r_shadow_lightcubemap;
1064 // this is the location of the eye in entity space
1065 static vec3_t r_shadow_entityeyeorigin;
1066 // this is the location of the light in entity space
1067 static vec3_t r_shadow_entitylightorigin;
1068 // this transforms entity coordinates to light filter cubemap coordinates
1069 // (also often used for other purposes)
1070 static matrix4x4_t r_shadow_entitytolight;
1071 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1072 // of attenuation texturing in full 3D (Z result often ignored)
1073 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1074 // this transforms only the Z to S, and T is always 0.5
1075 static matrix4x4_t r_shadow_entitytoattenuationz;
1076 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1077 static vec3_t r_shadow_entitylightcolorbase;
1078 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormap_pantscolor * ent->alpha
1079 static vec3_t r_shadow_entitylightcolorpants;
1080 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormap_shirtcolor * ent->alpha
1081 static vec3_t r_shadow_entitylightcolorshirt;
1083 static int r_shadow_lightpermutation;
1084 static int r_shadow_lightprog;
1086 void R_Shadow_Stage_Begin(void)
1090 R_Shadow_ValidateCvars();
1092 if (!r_shadow_attenuation2dtexture
1093 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1094 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1095 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1096 R_Shadow_MakeTextures();
1098 memset(&m, 0, sizeof(m));
1099 GL_BlendFunc(GL_ONE, GL_ZERO);
1100 GL_DepthMask(false);
1103 GL_Color(0, 0, 0, 1);
1104 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1105 qglEnable(GL_CULL_FACE);
1106 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1107 r_shadowstage = R_SHADOWSTAGE_NONE;
1110 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1112 r_shadow_rtlight = rtlight;
1115 void R_Shadow_Stage_Reset(void)
1118 if (gl_support_stenciltwoside)
1119 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1120 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1122 qglUseProgramObjectARB(0);
1123 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1124 qglBegin(GL_TRIANGLES);
1128 memset(&m, 0, sizeof(m));
1132 void R_Shadow_Stage_StencilShadowVolumes(void)
1134 R_Shadow_Stage_Reset();
1135 GL_Color(1, 1, 1, 1);
1136 GL_ColorMask(0, 0, 0, 0);
1137 GL_BlendFunc(GL_ONE, GL_ZERO);
1138 GL_DepthMask(false);
1140 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1141 //if (r_shadow_shadow_polygonoffset.value != 0)
1143 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1144 // qglEnable(GL_POLYGON_OFFSET_FILL);
1147 // qglDisable(GL_POLYGON_OFFSET_FILL);
1148 qglDepthFunc(GL_LESS);
1149 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1150 qglEnable(GL_STENCIL_TEST);
1151 qglStencilFunc(GL_ALWAYS, 128, ~0);
1152 if (gl_ext_stenciltwoside.integer)
1154 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1155 qglDisable(GL_CULL_FACE);
1156 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1157 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1159 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1160 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1162 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1166 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1167 qglEnable(GL_CULL_FACE);
1169 // this is changed by every shadow render so its value here is unimportant
1170 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1172 GL_Clear(GL_STENCIL_BUFFER_BIT);
1176 void R_Shadow_Stage_Lighting(int stenciltest)
1179 R_Shadow_Stage_Reset();
1180 GL_BlendFunc(GL_ONE, GL_ONE);
1181 GL_DepthMask(false);
1183 qglPolygonOffset(0, 0);
1184 //qglDisable(GL_POLYGON_OFFSET_FILL);
1185 GL_Color(1, 1, 1, 1);
1186 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1187 qglDepthFunc(GL_EQUAL);
1188 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1189 qglEnable(GL_CULL_FACE);
1190 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1191 qglEnable(GL_STENCIL_TEST);
1193 qglDisable(GL_STENCIL_TEST);
1195 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1196 // only draw light where this geometry was already rendered AND the
1197 // stencil is 128 (values other than this mean shadow)
1198 qglStencilFunc(GL_EQUAL, 128, ~0);
1199 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1201 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1202 memset(&m, 0, sizeof(m));
1203 m.pointer_vertex = varray_vertex3f;
1204 m.pointer_texcoord[0] = varray_texcoord2f[0];
1205 m.pointer_texcoord3f[1] = varray_svector3f;
1206 m.pointer_texcoord3f[2] = varray_tvector3f;
1207 m.pointer_texcoord3f[3] = varray_normal3f;
1208 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1209 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1210 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1211 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1212 // TODO: support fog (after renderer is converted to texture fog)
1213 m.tex[4] = R_GetTexture(r_texture_white); // fog
1214 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1216 GL_BlendFunc(GL_ONE, GL_ONE);
1217 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1219 r_shadow_lightpermutation = 0;
1220 // only add a feature to the permutation if that permutation exists
1221 // (otherwise it might end up not using a shader at all, which looks
1222 // worse than using less features)
1223 if (r_shadow_rtlight->specularscale && r_shadow_gloss.integer >= 1 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1224 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1225 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1226 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1227 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1228 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1229 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1230 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1231 if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
1232 r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
1233 if (r_shadow_glsl_usehalffloat.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
1234 r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
1235 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1236 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1237 // TODO: support fog (after renderer is converted to texture fog)
1238 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1240 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1242 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1243 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1244 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1246 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1247 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1249 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1250 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1251 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1253 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1255 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1257 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1258 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1261 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1262 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1264 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1267 void R_Shadow_Stage_VisibleShadowVolumes(void)
1269 R_Shadow_Stage_Reset();
1270 GL_BlendFunc(GL_ONE, GL_ONE);
1271 GL_DepthMask(false);
1272 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1273 qglPolygonOffset(0, 0);
1274 GL_Color(0.0, 0.0125, 0.1, 1);
1275 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1276 qglDepthFunc(GL_GEQUAL);
1277 qglCullFace(GL_FRONT); // this culls back
1278 qglDisable(GL_CULL_FACE);
1279 qglDisable(GL_STENCIL_TEST);
1280 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1283 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1285 R_Shadow_Stage_Reset();
1286 GL_BlendFunc(GL_ONE, GL_ONE);
1287 GL_DepthMask(false);
1288 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1289 qglPolygonOffset(0, 0);
1290 GL_Color(0.1, 0.0125, 0, 1);
1291 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1292 qglDepthFunc(GL_EQUAL);
1293 qglCullFace(GL_FRONT); // this culls back
1294 qglEnable(GL_CULL_FACE);
1296 qglEnable(GL_STENCIL_TEST);
1298 qglDisable(GL_STENCIL_TEST);
1299 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1302 void R_Shadow_Stage_End(void)
1304 R_Shadow_Stage_Reset();
1305 R_Shadow_Stage_ActiveLight(NULL);
1306 GL_BlendFunc(GL_ONE, GL_ZERO);
1309 qglPolygonOffset(0, 0);
1310 //qglDisable(GL_POLYGON_OFFSET_FILL);
1311 GL_Color(1, 1, 1, 1);
1312 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1313 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1314 qglDepthFunc(GL_LEQUAL);
1315 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1316 qglDisable(GL_STENCIL_TEST);
1317 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1318 if (gl_support_stenciltwoside)
1319 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1321 qglStencilFunc(GL_ALWAYS, 128, ~0);
1322 r_shadowstage = R_SHADOWSTAGE_NONE;
1325 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1327 int i, ix1, iy1, ix2, iy2;
1328 float x1, y1, x2, y2;
1331 mplane_t planes[11];
1332 float vertex3f[256*3];
1334 // if view is inside the light box, just say yes it's visible
1335 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1337 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1341 // create a temporary brush describing the area the light can affect in worldspace
1342 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1343 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1344 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1345 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1346 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1347 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1348 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1349 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1350 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1351 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1352 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1354 // turn the brush into a mesh
1355 memset(&mesh, 0, sizeof(rmesh_t));
1356 mesh.maxvertices = 256;
1357 mesh.vertex3f = vertex3f;
1358 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1359 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1361 // if that mesh is empty, the light is not visible at all
1362 if (!mesh.numvertices)
1365 if (!r_shadow_scissor.integer)
1368 // if that mesh is not empty, check what area of the screen it covers
1369 x1 = y1 = x2 = y2 = 0;
1371 for (i = 0;i < mesh.numvertices;i++)
1373 VectorCopy(mesh.vertex3f + i * 3, v);
1374 GL_TransformToScreen(v, v2);
1375 //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]);
1378 if (x1 > v2[0]) x1 = v2[0];
1379 if (x2 < v2[0]) x2 = v2[0];
1380 if (y1 > v2[1]) y1 = v2[1];
1381 if (y2 < v2[1]) y2 = v2[1];
1390 // now convert the scissor rectangle to integer screen coordinates
1395 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1397 // clamp it to the screen
1398 if (ix1 < r_view_x) ix1 = r_view_x;
1399 if (iy1 < r_view_y) iy1 = r_view_y;
1400 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1401 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1403 // if it is inside out, it's not visible
1404 if (ix2 <= ix1 || iy2 <= iy1)
1407 // the light area is visible, set up the scissor rectangle
1408 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1409 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1410 //qglEnable(GL_SCISSOR_TEST);
1415 extern float *rsurface_vertex3f;
1416 extern float *rsurface_svector3f;
1417 extern float *rsurface_tvector3f;
1418 extern float *rsurface_normal3f;
1419 extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
1421 static void R_Shadow_VertexShadingWithXYZAttenuation(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1423 int numverts = surface->num_vertices;
1424 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1425 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1426 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1427 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1428 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1430 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1431 if ((dist = DotProduct(v, v)) < 1)
1434 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1435 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1436 if ((dot = DotProduct(n, v)) > 0)
1438 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1439 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
1440 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
1441 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
1445 color4f[0] = ambientcolor[0] * distintensity - reduce;
1446 color4f[1] = ambientcolor[1] * distintensity - reduce;
1447 color4f[2] = ambientcolor[2] * distintensity - reduce;
1449 color4f[0] = bound(0, color4f[0], 1);
1450 color4f[1] = bound(0, color4f[1], 1);
1451 color4f[2] = bound(0, color4f[2], 1);
1454 VectorClear(color4f);
1459 static void R_Shadow_VertexShadingWithZAttenuation(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1461 int numverts = surface->num_vertices;
1462 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1463 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1464 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1465 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1466 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1468 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1469 if ((dist = fabs(v[2])) < 1)
1471 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1472 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1473 if ((dot = DotProduct(n, v)) > 0)
1475 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1476 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
1477 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
1478 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
1482 color4f[0] = ambientcolor[0] * distintensity - reduce;
1483 color4f[1] = ambientcolor[1] * distintensity - reduce;
1484 color4f[2] = ambientcolor[2] * distintensity - reduce;
1486 color4f[0] = bound(0, color4f[0], 1);
1487 color4f[1] = bound(0, color4f[1], 1);
1488 color4f[2] = bound(0, color4f[2], 1);
1491 VectorClear(color4f);
1496 static void R_Shadow_VertexShading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1498 int numverts = surface->num_vertices;
1499 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1500 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1501 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1502 float dot, shadeintensity, v[3], n[3];
1503 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1505 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1506 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1507 if ((dot = DotProduct(n, v)) > 0)
1509 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1510 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) - reduce;
1511 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) - reduce;
1512 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) - reduce;
1513 color4f[0] = bound(0, color4f[0], 1);
1514 color4f[1] = bound(0, color4f[1], 1);
1515 color4f[2] = bound(0, color4f[2], 1);
1518 VectorClear(color4f);
1523 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1524 #define USETEXMATRIX
1526 #ifndef USETEXMATRIX
1527 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1528 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1529 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1533 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1534 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1535 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1542 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1546 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1547 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1555 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)
1559 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1561 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1562 // the cubemap normalizes this for us
1563 out3f[0] = DotProduct(svector3f, lightdir);
1564 out3f[1] = DotProduct(tvector3f, lightdir);
1565 out3f[2] = DotProduct(normal3f, lightdir);
1569 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)
1572 float lightdir[3], eyedir[3], halfdir[3];
1573 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1575 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1576 VectorNormalize(lightdir);
1577 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1578 VectorNormalize(eyedir);
1579 VectorAdd(lightdir, eyedir, halfdir);
1580 // the cubemap normalizes this for us
1581 out3f[0] = DotProduct(svector3f, halfdir);
1582 out3f[1] = DotProduct(tvector3f, halfdir);
1583 out3f[2] = DotProduct(normal3f, halfdir);
1587 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)
1589 // used to display how many times a surface is lit for level design purposes
1590 int surfacelistindex;
1592 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1593 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1594 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1595 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1596 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1597 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1598 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1599 if (!doambientbase && !dodiffusebase && !doambientpants && !dodiffusepants && !doambientshirt && !dodiffuseshirt && !dospecular)
1601 GL_Color(0.1, 0.025, 0, 1);
1602 memset(&m, 0, sizeof(m));
1604 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1606 const msurface_t *surface = surfacelist[surfacelistindex];
1607 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1608 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1609 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
1610 GL_LockArrays(0, 0);
1614 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)
1616 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1617 int surfacelistindex;
1618 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1619 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1620 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1621 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1622 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1623 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1624 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1625 // TODO: add direct pants/shirt rendering
1626 if (doambientpants || dodiffusepants)
1627 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);
1628 if (doambientshirt || dodiffuseshirt)
1629 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);
1630 if (!doambientbase && !dodiffusebase && !dospecular)
1632 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
1633 R_Mesh_TexBind(0, R_GetTexture(normalmaptexture));
1634 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1635 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1636 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1638 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1640 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1641 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1643 const msurface_t *surface = surfacelist[surfacelistindex];
1644 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1645 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1646 if (!rsurface_svector3f)
1648 rsurface_svector3f = varray_svector3f;
1649 rsurface_tvector3f = varray_tvector3f;
1650 rsurface_normal3f = varray_normal3f;
1651 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);
1653 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1654 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1655 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1656 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1657 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1658 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1660 c_rt_lighttris += surface->num_triangles;
1661 GL_LockArrays(0, 0);
1665 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)
1667 // ARB path (any Geforce, any Radeon)
1668 int surfacelistindex;
1670 float color2[3], colorscale;
1672 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1673 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1674 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1675 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1676 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1677 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1678 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1679 // TODO: add direct pants/shirt rendering
1680 if (doambientpants || dodiffusepants)
1681 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);
1682 if (doambientshirt || dodiffuseshirt)
1683 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);
1684 if (!doambientbase && !dodiffusebase && !dospecular)
1686 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1688 const msurface_t *surface = surfacelist[surfacelistindex];
1689 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1690 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1691 if (!rsurface_svector3f)
1693 rsurface_svector3f = varray_svector3f;
1694 rsurface_tvector3f = varray_tvector3f;
1695 rsurface_normal3f = varray_normal3f;
1696 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);
1701 colorscale = r_shadow_rtlight->ambientscale;
1702 // colorscale accounts for how much we multiply the brightness
1705 // mult is how many times the final pass of the lighting will be
1706 // performed to get more brightness than otherwise possible.
1708 // Limit mult to 64 for sanity sake.
1709 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1711 // 3 3D combine path (Geforce3, Radeon 8500)
1712 memset(&m, 0, sizeof(m));
1713 m.pointer_vertex = rsurface_vertex3f;
1714 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1716 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1717 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1719 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1720 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1722 m.tex[1] = R_GetTexture(basetexture);
1723 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1724 m.texmatrix[1] = texture->currenttexmatrix;
1725 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1727 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1728 m.texmatrix[2] = r_shadow_entitytolight;
1730 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1731 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1733 GL_BlendFunc(GL_ONE, GL_ONE);
1735 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1737 // 2 3D combine path (Geforce3, original Radeon)
1738 memset(&m, 0, sizeof(m));
1739 m.pointer_vertex = rsurface_vertex3f;
1740 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1742 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1743 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1745 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1746 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1748 m.tex[1] = R_GetTexture(basetexture);
1749 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1750 m.texmatrix[1] = texture->currenttexmatrix;
1751 GL_BlendFunc(GL_ONE, GL_ONE);
1753 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1755 // 4 2D combine path (Geforce3, Radeon 8500)
1756 memset(&m, 0, sizeof(m));
1757 m.pointer_vertex = rsurface_vertex3f;
1758 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1760 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1761 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1763 m.pointer_texcoord[0] = varray_texcoord2f[0];
1764 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1766 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1768 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1769 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1771 m.pointer_texcoord[1] = varray_texcoord2f[1];
1772 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1774 m.tex[2] = R_GetTexture(basetexture);
1775 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1776 m.texmatrix[2] = texture->currenttexmatrix;
1777 if (r_shadow_lightcubemap != r_texture_whitecube)
1779 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1781 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1782 m.texmatrix[3] = r_shadow_entitytolight;
1784 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1785 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1788 GL_BlendFunc(GL_ONE, GL_ONE);
1790 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1792 // 3 2D combine path (Geforce3, original Radeon)
1793 memset(&m, 0, sizeof(m));
1794 m.pointer_vertex = rsurface_vertex3f;
1795 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1797 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1798 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1800 m.pointer_texcoord[0] = varray_texcoord2f[0];
1801 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1803 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1805 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1806 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1808 m.pointer_texcoord[1] = varray_texcoord2f[1];
1809 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1811 m.tex[2] = R_GetTexture(basetexture);
1812 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1813 m.texmatrix[2] = texture->currenttexmatrix;
1814 GL_BlendFunc(GL_ONE, GL_ONE);
1818 // 2/2/2 2D combine path (any dot3 card)
1819 memset(&m, 0, sizeof(m));
1820 m.pointer_vertex = rsurface_vertex3f;
1821 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1823 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1824 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1826 m.pointer_texcoord[0] = varray_texcoord2f[0];
1827 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1829 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1831 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1832 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1834 m.pointer_texcoord[1] = varray_texcoord2f[1];
1835 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1838 GL_ColorMask(0,0,0,1);
1839 GL_BlendFunc(GL_ONE, GL_ZERO);
1840 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1841 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1842 GL_LockArrays(0, 0);
1844 c_rt_lighttris += surface->num_triangles;
1846 memset(&m, 0, sizeof(m));
1847 m.pointer_vertex = rsurface_vertex3f;
1848 m.tex[0] = R_GetTexture(basetexture);
1849 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1850 m.texmatrix[0] = texture->currenttexmatrix;
1851 if (r_shadow_lightcubemap != r_texture_whitecube)
1853 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1855 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1856 m.texmatrix[1] = r_shadow_entitytolight;
1858 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1859 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1862 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1864 // this final code is shared
1866 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1867 VectorScale(lightcolorbase, colorscale, color2);
1868 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1869 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1871 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1872 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1874 c_rt_lighttris += surface->num_triangles;
1876 GL_LockArrays(0, 0);
1881 colorscale = r_shadow_rtlight->diffusescale;
1882 // colorscale accounts for how much we multiply the brightness
1885 // mult is how many times the final pass of the lighting will be
1886 // performed to get more brightness than otherwise possible.
1888 // Limit mult to 64 for sanity sake.
1889 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1891 // 3/2 3D combine path (Geforce3, Radeon 8500)
1892 memset(&m, 0, sizeof(m));
1893 m.pointer_vertex = rsurface_vertex3f;
1894 m.tex[0] = R_GetTexture(normalmaptexture);
1895 m.texcombinergb[0] = GL_REPLACE;
1896 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1897 m.texmatrix[0] = texture->currenttexmatrix;
1898 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1899 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1900 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1901 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);
1902 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1904 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1905 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1907 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1908 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1911 GL_ColorMask(0,0,0,1);
1912 GL_BlendFunc(GL_ONE, GL_ZERO);
1913 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1914 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1915 GL_LockArrays(0, 0);
1917 c_rt_lighttris += surface->num_triangles;
1919 memset(&m, 0, sizeof(m));
1920 m.pointer_vertex = rsurface_vertex3f;
1921 m.tex[0] = R_GetTexture(basetexture);
1922 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1923 m.texmatrix[0] = texture->currenttexmatrix;
1924 if (r_shadow_lightcubemap != r_texture_whitecube)
1926 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1928 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1929 m.texmatrix[1] = r_shadow_entitytolight;
1931 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1932 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1935 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1937 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1939 // 1/2/2 3D combine path (original Radeon)
1940 memset(&m, 0, sizeof(m));
1941 m.pointer_vertex = rsurface_vertex3f;
1942 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1944 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1945 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1947 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1948 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1951 GL_ColorMask(0,0,0,1);
1952 GL_BlendFunc(GL_ONE, GL_ZERO);
1953 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1954 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1955 GL_LockArrays(0, 0);
1957 c_rt_lighttris += surface->num_triangles;
1959 memset(&m, 0, sizeof(m));
1960 m.pointer_vertex = rsurface_vertex3f;
1961 m.tex[0] = R_GetTexture(normalmaptexture);
1962 m.texcombinergb[0] = GL_REPLACE;
1963 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1964 m.texmatrix[0] = texture->currenttexmatrix;
1965 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1966 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1967 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1968 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);
1970 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1971 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1972 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1973 GL_LockArrays(0, 0);
1975 c_rt_lighttris += surface->num_triangles;
1977 memset(&m, 0, sizeof(m));
1978 m.pointer_vertex = rsurface_vertex3f;
1979 m.tex[0] = R_GetTexture(basetexture);
1980 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1981 m.texmatrix[0] = texture->currenttexmatrix;
1982 if (r_shadow_lightcubemap != r_texture_whitecube)
1984 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1986 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1987 m.texmatrix[1] = r_shadow_entitytolight;
1989 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1990 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1993 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1995 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1997 // 2/2 3D combine path (original Radeon)
1998 memset(&m, 0, sizeof(m));
1999 m.pointer_vertex = rsurface_vertex3f;
2000 m.tex[0] = R_GetTexture(normalmaptexture);
2001 m.texcombinergb[0] = GL_REPLACE;
2002 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2003 m.texmatrix[0] = texture->currenttexmatrix;
2004 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2005 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2006 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2007 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);
2009 GL_ColorMask(0,0,0,1);
2010 GL_BlendFunc(GL_ONE, GL_ZERO);
2011 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2012 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2013 GL_LockArrays(0, 0);
2015 c_rt_lighttris += surface->num_triangles;
2017 memset(&m, 0, sizeof(m));
2018 m.pointer_vertex = rsurface_vertex3f;
2019 m.tex[0] = R_GetTexture(basetexture);
2020 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2021 m.texmatrix[0] = texture->currenttexmatrix;
2022 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2024 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2025 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2027 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2028 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2030 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2032 else if (r_textureunits.integer >= 4)
2034 // 4/2 2D combine path (Geforce3, Radeon 8500)
2035 memset(&m, 0, sizeof(m));
2036 m.pointer_vertex = rsurface_vertex3f;
2037 m.tex[0] = R_GetTexture(normalmaptexture);
2038 m.texcombinergb[0] = GL_REPLACE;
2039 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2040 m.texmatrix[0] = texture->currenttexmatrix;
2041 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2042 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2043 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2044 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);
2045 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2047 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2048 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2050 m.pointer_texcoord[2] = varray_texcoord2f[2];
2051 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2053 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2055 m.pointer_texcoord3f[3] = rsurface_vertex3f;
2056 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2058 m.pointer_texcoord[3] = varray_texcoord2f[3];
2059 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2062 GL_ColorMask(0,0,0,1);
2063 GL_BlendFunc(GL_ONE, GL_ZERO);
2064 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2065 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2066 GL_LockArrays(0, 0);
2068 c_rt_lighttris += surface->num_triangles;
2070 memset(&m, 0, sizeof(m));
2071 m.pointer_vertex = rsurface_vertex3f;
2072 m.tex[0] = R_GetTexture(basetexture);
2073 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2074 m.texmatrix[0] = texture->currenttexmatrix;
2075 if (r_shadow_lightcubemap != r_texture_whitecube)
2077 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2079 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2080 m.texmatrix[1] = r_shadow_entitytolight;
2082 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2083 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2086 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2090 // 2/2/2 2D combine path (any dot3 card)
2091 memset(&m, 0, sizeof(m));
2092 m.pointer_vertex = rsurface_vertex3f;
2093 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2095 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2096 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2098 m.pointer_texcoord[0] = varray_texcoord2f[0];
2099 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2101 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2103 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2104 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2106 m.pointer_texcoord[1] = varray_texcoord2f[1];
2107 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2110 GL_ColorMask(0,0,0,1);
2111 GL_BlendFunc(GL_ONE, GL_ZERO);
2112 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2113 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2114 GL_LockArrays(0, 0);
2116 c_rt_lighttris += surface->num_triangles;
2118 memset(&m, 0, sizeof(m));
2119 m.pointer_vertex = rsurface_vertex3f;
2120 m.tex[0] = R_GetTexture(normalmaptexture);
2121 m.texcombinergb[0] = GL_REPLACE;
2122 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2123 m.texmatrix[0] = texture->currenttexmatrix;
2124 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2125 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2126 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2127 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);
2129 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2130 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2131 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2132 GL_LockArrays(0, 0);
2134 c_rt_lighttris += surface->num_triangles;
2136 memset(&m, 0, sizeof(m));
2137 m.pointer_vertex = rsurface_vertex3f;
2138 m.tex[0] = R_GetTexture(basetexture);
2139 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2140 m.texmatrix[0] = texture->currenttexmatrix;
2141 if (r_shadow_lightcubemap != r_texture_whitecube)
2143 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2145 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2146 m.texmatrix[1] = r_shadow_entitytolight;
2148 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2149 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2152 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2154 // this final code is shared
2156 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2157 VectorScale(lightcolorbase, colorscale, color2);
2158 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2159 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2161 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2162 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2164 c_rt_lighttris += surface->num_triangles;
2166 GL_LockArrays(0, 0);
2170 // FIXME: detect blendsquare!
2171 //if (gl_support_blendsquare)
2173 colorscale = specularscale;
2175 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2177 // 2/0/0/1/2 3D combine blendsquare path
2178 memset(&m, 0, sizeof(m));
2179 m.pointer_vertex = rsurface_vertex3f;
2180 m.tex[0] = R_GetTexture(normalmaptexture);
2181 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2182 m.texmatrix[0] = texture->currenttexmatrix;
2183 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2184 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2185 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2186 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);
2188 GL_ColorMask(0,0,0,1);
2189 // this squares the result
2190 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2191 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2192 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2193 GL_LockArrays(0, 0);
2195 c_rt_lighttris += surface->num_triangles;
2197 memset(&m, 0, sizeof(m));
2198 m.pointer_vertex = rsurface_vertex3f;
2200 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2201 // square alpha in framebuffer a few times to make it shiny
2202 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2203 // these comments are a test run through this math for intensity 0.5
2204 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2205 // 0.25 * 0.25 = 0.0625 (this is another pass)
2206 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2207 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2209 c_rt_lighttris += surface->num_triangles;
2210 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2212 c_rt_lighttris += surface->num_triangles;
2213 GL_LockArrays(0, 0);
2215 memset(&m, 0, sizeof(m));
2216 m.pointer_vertex = rsurface_vertex3f;
2217 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2219 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2220 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2222 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2223 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2226 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2227 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2228 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2229 GL_LockArrays(0, 0);
2231 c_rt_lighttris += surface->num_triangles;
2233 memset(&m, 0, sizeof(m));
2234 m.pointer_vertex = rsurface_vertex3f;
2235 m.tex[0] = R_GetTexture(glosstexture);
2236 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2237 m.texmatrix[0] = texture->currenttexmatrix;
2238 if (r_shadow_lightcubemap != r_texture_whitecube)
2240 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2242 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2243 m.texmatrix[1] = r_shadow_entitytolight;
2245 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2246 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2249 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2251 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2253 // 2/0/0/2 3D combine blendsquare path
2254 memset(&m, 0, sizeof(m));
2255 m.pointer_vertex = rsurface_vertex3f;
2256 m.tex[0] = R_GetTexture(normalmaptexture);
2257 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2258 m.texmatrix[0] = texture->currenttexmatrix;
2259 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2260 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2261 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2262 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);
2264 GL_ColorMask(0,0,0,1);
2265 // this squares the result
2266 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2267 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2268 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2269 GL_LockArrays(0, 0);
2271 c_rt_lighttris += surface->num_triangles;
2273 memset(&m, 0, sizeof(m));
2274 m.pointer_vertex = rsurface_vertex3f;
2276 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2277 // square alpha in framebuffer a few times to make it shiny
2278 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2279 // these comments are a test run through this math for intensity 0.5
2280 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2281 // 0.25 * 0.25 = 0.0625 (this is another pass)
2282 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2283 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2285 c_rt_lighttris += surface->num_triangles;
2286 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2288 c_rt_lighttris += surface->num_triangles;
2289 GL_LockArrays(0, 0);
2291 memset(&m, 0, sizeof(m));
2292 m.pointer_vertex = rsurface_vertex3f;
2293 m.tex[0] = R_GetTexture(glosstexture);
2294 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2295 m.texmatrix[0] = texture->currenttexmatrix;
2296 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2298 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2299 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2301 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2302 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2304 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2308 // 2/0/0/2/2 2D combine blendsquare path
2309 memset(&m, 0, sizeof(m));
2310 m.pointer_vertex = rsurface_vertex3f;
2311 m.tex[0] = R_GetTexture(normalmaptexture);
2312 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2313 m.texmatrix[0] = texture->currenttexmatrix;
2314 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2315 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2316 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2317 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);
2319 GL_ColorMask(0,0,0,1);
2320 // this squares the result
2321 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2322 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2323 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2324 GL_LockArrays(0, 0);
2326 c_rt_lighttris += surface->num_triangles;
2328 memset(&m, 0, sizeof(m));
2329 m.pointer_vertex = rsurface_vertex3f;
2331 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2332 // square alpha in framebuffer a few times to make it shiny
2333 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2334 // these comments are a test run through this math for intensity 0.5
2335 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2336 // 0.25 * 0.25 = 0.0625 (this is another pass)
2337 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2338 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2340 c_rt_lighttris += surface->num_triangles;
2341 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2343 c_rt_lighttris += surface->num_triangles;
2344 GL_LockArrays(0, 0);
2346 memset(&m, 0, sizeof(m));
2347 m.pointer_vertex = rsurface_vertex3f;
2348 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2350 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2351 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2353 m.pointer_texcoord[0] = varray_texcoord2f[0];
2354 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2356 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2358 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2359 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2361 m.pointer_texcoord[1] = varray_texcoord2f[1];
2362 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2365 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2366 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2367 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2368 GL_LockArrays(0, 0);
2370 c_rt_lighttris += surface->num_triangles;
2372 memset(&m, 0, sizeof(m));
2373 m.pointer_vertex = rsurface_vertex3f;
2374 m.tex[0] = R_GetTexture(glosstexture);
2375 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2376 m.texmatrix[0] = texture->currenttexmatrix;
2377 if (r_shadow_lightcubemap != r_texture_whitecube)
2379 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2381 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2382 m.texmatrix[1] = r_shadow_entitytolight;
2384 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2385 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2388 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2391 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2392 VectorScale(lightcolorbase, colorscale, color2);
2393 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2394 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2396 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2397 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2399 c_rt_lighttris += surface->num_triangles;
2401 GL_LockArrays(0, 0);
2407 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)
2409 int surfacelistindex;
2411 float ambientcolor2[3], diffusecolor2[3];
2413 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
2414 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
2415 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
2416 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
2417 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
2418 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
2419 //qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
2420 // TODO: add direct pants/shirt rendering
2421 if (doambientpants || dodiffusepants)
2422 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);
2423 if (doambientshirt || dodiffuseshirt)
2424 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);
2425 if (!doambientbase && !dodiffusebase)
2427 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, ambientcolor2);
2428 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, diffusecolor2);
2429 GL_BlendFunc(GL_ONE, GL_ONE);
2430 memset(&m, 0, sizeof(m));
2431 m.tex[0] = R_GetTexture(basetexture);
2432 if (r_textureunits.integer >= 2)
2435 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2437 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2439 m.pointer_texcoord[1] = varray_texcoord2f[1];
2440 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2442 if (r_textureunits.integer >= 3)
2444 // Geforce3/Radeon class but not using dot3
2445 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2447 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2449 m.pointer_texcoord[2] = varray_texcoord2f[2];
2450 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2454 m.pointer_color = varray_color4f;
2456 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2458 const msurface_t *surface = surfacelist[surfacelistindex];
2459 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2460 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2461 if (!rsurface_svector3f)
2463 rsurface_svector3f = varray_svector3f;
2464 rsurface_tvector3f = varray_tvector3f;
2465 rsurface_normal3f = varray_normal3f;
2466 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);
2468 // OpenGL 1.1 path (anything)
2469 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2470 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
2471 if (r_textureunits.integer >= 2)
2475 R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
2477 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2479 if (r_textureunits.integer >= 3)
2481 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2483 R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
2485 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2489 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
2491 if (r_textureunits.integer >= 3)
2492 R_Shadow_VertexShading(surface, diffusecolor2, ambientcolor2, renders);
2493 else if (r_textureunits.integer >= 2)
2494 R_Shadow_VertexShadingWithZAttenuation(surface, diffusecolor2, ambientcolor2, renders);
2496 R_Shadow_VertexShadingWithXYZAttenuation(surface, diffusecolor2, ambientcolor2, renders);
2497 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2498 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2499 GL_LockArrays(0, 0);
2501 c_rt_lighttris += surface->num_triangles;
2506 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)
2508 // FIXME: support MATERIALFLAG_NODEPTHTEST
2509 switch (r_shadowstage)
2511 case R_SHADOWSTAGE_VISIBLELIGHTING:
2512 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2514 case R_SHADOWSTAGE_LIGHT_GLSL:
2515 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);
2517 case R_SHADOWSTAGE_LIGHT_DOT3:
2518 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);
2520 case R_SHADOWSTAGE_LIGHT_VERTEX:
2521 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);
2524 Con_Printf("R_Shadow_RenderLighting: unknown r_shadowstage %i\n", r_shadowstage);
2529 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2533 R_RTLight_Uncompile(rtlight);
2534 memset(rtlight, 0, sizeof(*rtlight));
2536 VectorCopy(light->origin, rtlight->shadoworigin);
2537 VectorCopy(light->color, rtlight->color);
2538 rtlight->radius = light->radius;
2539 //rtlight->cullradius = rtlight->radius;
2540 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2541 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2542 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2543 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2544 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2545 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2546 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2547 rtlight->cubemapname[0] = 0;
2548 if (light->cubemapname[0])
2549 strcpy(rtlight->cubemapname, light->cubemapname);
2550 else if (light->cubemapnum > 0)
2551 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2552 rtlight->shadow = light->shadow;
2553 rtlight->corona = light->corona;
2554 rtlight->style = light->style;
2555 rtlight->isstatic = isstatic;
2556 rtlight->coronasizescale = light->coronasizescale;
2557 rtlight->ambientscale = light->ambientscale;
2558 rtlight->diffusescale = light->diffusescale;
2559 rtlight->specularscale = light->specularscale;
2560 rtlight->flags = light->flags;
2561 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2562 // ConcatScale won't work here because this needs to scale rotate and
2563 // translate, not just rotate
2564 scale = 1.0f / rtlight->radius;
2565 for (k = 0;k < 3;k++)
2566 for (j = 0;j < 4;j++)
2567 rtlight->matrix_worldtolight.m[k][j] *= scale;
2569 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2570 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2571 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2572 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2575 // compiles rtlight geometry
2576 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2577 void R_RTLight_Compile(rtlight_t *rtlight)
2579 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2580 entity_render_t *ent = r_refdef.worldentity;
2581 model_t *model = r_refdef.worldmodel;
2584 // compile the light
2585 rtlight->compiled = true;
2586 rtlight->static_numleafs = 0;
2587 rtlight->static_numleafpvsbytes = 0;
2588 rtlight->static_leaflist = NULL;
2589 rtlight->static_leafpvs = NULL;
2590 rtlight->static_numsurfaces = 0;
2591 rtlight->static_surfacelist = NULL;
2592 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2593 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2594 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2595 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2596 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2597 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2599 if (model && model->GetLightInfo)
2601 // this variable must be set for the CompileShadowVolume code
2602 r_shadow_compilingrtlight = rtlight;
2603 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2604 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);
2605 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2606 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2607 rtlight->static_numleafs = numleafs;
2608 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2609 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2610 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2611 rtlight->static_numsurfaces = numsurfaces;
2612 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2614 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2615 if (numleafpvsbytes)
2616 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2618 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2619 if (model->CompileShadowVolume && rtlight->shadow)
2620 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2621 // now we're done compiling the rtlight
2622 r_shadow_compilingrtlight = NULL;
2626 // use smallest available cullradius - box radius or light radius
2627 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2628 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2632 if (rtlight->static_meshchain_shadow)
2635 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2638 shadowtris += mesh->numtriangles;
2642 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);
2645 void R_RTLight_Uncompile(rtlight_t *rtlight)
2647 if (rtlight->compiled)
2649 if (rtlight->static_meshchain_shadow)
2650 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2651 rtlight->static_meshchain_shadow = NULL;
2652 // these allocations are grouped
2653 if (rtlight->static_leaflist)
2654 Mem_Free(rtlight->static_leaflist);
2655 rtlight->static_numleafs = 0;
2656 rtlight->static_numleafpvsbytes = 0;
2657 rtlight->static_leaflist = NULL;
2658 rtlight->static_leafpvs = NULL;
2659 rtlight->static_numsurfaces = 0;
2660 rtlight->static_surfacelist = NULL;
2661 rtlight->compiled = false;
2665 void R_Shadow_UncompileWorldLights(void)
2668 for (light = r_shadow_worldlightchain;light;light = light->next)
2669 R_RTLight_Uncompile(&light->rtlight);
2672 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2674 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2675 vec_t relativeshadowradius;
2676 if (ent == r_refdef.worldentity)
2678 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2681 R_Mesh_Matrix(&ent->matrix);
2682 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2684 R_Mesh_VertexPointer(mesh->vertex3f);
2685 GL_LockArrays(0, mesh->numverts);
2686 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2688 // decrement stencil if backface is behind depthbuffer
2689 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2690 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2691 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2692 c_rtcached_shadowmeshes++;
2693 c_rtcached_shadowtris += mesh->numtriangles;
2694 // increment stencil if frontface is behind depthbuffer
2695 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2696 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2698 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2699 c_rtcached_shadowmeshes++;
2700 c_rtcached_shadowtris += mesh->numtriangles;
2701 GL_LockArrays(0, 0);
2704 else if (numsurfaces)
2706 R_Mesh_Matrix(&ent->matrix);
2707 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2712 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2713 relativeshadowradius = rtlight->radius / ent->scale;
2714 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2715 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2716 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2717 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2718 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2719 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2720 R_Mesh_Matrix(&ent->matrix);
2721 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2725 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
2727 // set up properties for rendering light onto this entity
2728 r_shadow_entitylightcolorbase[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2729 r_shadow_entitylightcolorbase[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2730 r_shadow_entitylightcolorbase[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2731 r_shadow_entitylightcolorpants[0] = lightcolor[0] * ent->colormap_pantscolor[0] * ent->alpha;
2732 r_shadow_entitylightcolorpants[1] = lightcolor[1] * ent->colormap_pantscolor[1] * ent->alpha;
2733 r_shadow_entitylightcolorpants[2] = lightcolor[2] * ent->colormap_pantscolor[2] * ent->alpha;
2734 r_shadow_entitylightcolorshirt[0] = lightcolor[0] * ent->colormap_shirtcolor[0] * ent->alpha;
2735 r_shadow_entitylightcolorshirt[1] = lightcolor[1] * ent->colormap_shirtcolor[1] * ent->alpha;
2736 r_shadow_entitylightcolorshirt[2] = lightcolor[2] * ent->colormap_shirtcolor[2] * ent->alpha;
2737 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2738 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2739 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2740 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2741 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2742 R_Mesh_Matrix(&ent->matrix);
2743 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2745 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2746 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2747 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2748 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2750 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2753 if (ent == r_refdef.worldentity)
2754 ent->model->DrawLight(ent, r_shadow_entitylightcolorbase, r_shadow_entitylightcolorpants, r_shadow_entitylightcolorshirt, numsurfaces, surfacelist);
2756 ent->model->DrawLight(ent, r_shadow_entitylightcolorbase, r_shadow_entitylightcolorpants, r_shadow_entitylightcolorshirt, ent->model->nummodelsurfaces, ent->model->surfacelist);
2759 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2764 int numleafs, numsurfaces;
2765 int *leaflist, *surfacelist;
2767 int numlightentities;
2768 int numshadowentities;
2769 entity_render_t *lightentities[MAX_EDICTS];
2770 entity_render_t *shadowentities[MAX_EDICTS];
2772 // skip lights that don't light (corona only lights)
2773 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < (1.0f / 32768.0f))
2776 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2777 VectorScale(rtlight->color, f, lightcolor);
2778 if (VectorLength2(lightcolor) < (1.0f / 32768.0f))
2781 if (rtlight->selected)
2783 f = 2 + sin(realtime * M_PI * 4.0);
2784 VectorScale(lightcolor, f, lightcolor);
2788 // loading is done before visibility checks because loading should happen
2789 // all at once at the start of a level, not when it stalls gameplay.
2790 // (especially important to benchmarks)
2792 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2793 R_RTLight_Compile(rtlight);
2795 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2797 // if the light box is offscreen, skip it
2798 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2801 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2803 // compiled light, world available and can receive realtime lighting
2804 // retrieve leaf information
2805 numleafs = rtlight->static_numleafs;
2806 leaflist = rtlight->static_leaflist;
2807 leafpvs = rtlight->static_leafpvs;
2808 numsurfaces = rtlight->static_numsurfaces;
2809 surfacelist = rtlight->static_surfacelist;
2811 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2813 // dynamic light, world available and can receive realtime lighting
2814 // calculate lit surfaces and leafs
2815 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2816 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);
2817 leaflist = r_shadow_buffer_leaflist;
2818 leafpvs = r_shadow_buffer_leafpvs;
2819 surfacelist = r_shadow_buffer_surfacelist;
2820 // if the reduced leaf bounds are offscreen, skip it
2821 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2833 // check if light is illuminating any visible leafs
2836 for (i = 0;i < numleafs;i++)
2837 if (r_worldleafvisible[leaflist[i]])
2842 // set up a scissor rectangle for this light
2843 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2846 numlightentities = 0;
2848 lightentities[numlightentities++] = r_refdef.worldentity;
2849 numshadowentities = 0;
2851 shadowentities[numshadowentities++] = r_refdef.worldentity;
2852 if (r_drawentities.integer)
2854 for (i = 0;i < r_refdef.numentities;i++)
2856 entity_render_t *ent = r_refdef.entities[i];
2857 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2859 && !(ent->flags & RENDER_TRANSPARENT)
2860 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2862 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2863 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2864 shadowentities[numshadowentities++] = ent;
2865 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2866 lightentities[numlightentities++] = ent;
2871 // return if there's nothing at all to light
2872 if (!numlightentities)
2875 R_Shadow_Stage_ActiveLight(rtlight);
2879 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2882 R_Shadow_Stage_StencilShadowVolumes();
2883 for (i = 0;i < numshadowentities;i++)
2884 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2887 if (numlightentities && !visible)
2889 R_Shadow_Stage_Lighting(usestencil);
2890 for (i = 0;i < numlightentities;i++)
2891 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2894 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2896 R_Shadow_Stage_VisibleShadowVolumes();
2897 for (i = 0;i < numshadowentities;i++)
2898 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2901 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2903 R_Shadow_Stage_VisibleLighting(usestencil);
2904 for (i = 0;i < numlightentities;i++)
2905 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2909 void R_ShadowVolumeLighting(qboolean visible)
2914 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2915 R_Shadow_EditLights_Reload_f();
2917 R_Shadow_Stage_Begin();
2919 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2920 if (r_shadow_debuglight.integer >= 0)
2922 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2923 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2924 R_DrawRTLight(&light->rtlight, visible);
2927 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2928 if (light->flags & flag)
2929 R_DrawRTLight(&light->rtlight, visible);
2931 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2932 R_DrawRTLight(&light->rtlight, visible);
2934 R_Shadow_Stage_End();
2937 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2938 typedef struct suffixinfo_s
2941 qboolean flipx, flipy, flipdiagonal;
2944 static suffixinfo_t suffix[3][6] =
2947 {"px", false, false, false},
2948 {"nx", false, false, false},
2949 {"py", false, false, false},
2950 {"ny", false, false, false},
2951 {"pz", false, false, false},
2952 {"nz", false, false, false}
2955 {"posx", false, false, false},
2956 {"negx", false, false, false},
2957 {"posy", false, false, false},
2958 {"negy", false, false, false},
2959 {"posz", false, false, false},
2960 {"negz", false, false, false}
2963 {"rt", true, false, true},
2964 {"lf", false, true, true},
2965 {"ft", true, true, false},
2966 {"bk", false, false, false},
2967 {"up", true, false, true},
2968 {"dn", true, false, true}
2972 static int componentorder[4] = {0, 1, 2, 3};
2974 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2976 int i, j, cubemapsize;
2977 qbyte *cubemappixels, *image_rgba;
2978 rtexture_t *cubemaptexture;
2980 // must start 0 so the first loadimagepixels has no requested width/height
2982 cubemappixels = NULL;
2983 cubemaptexture = NULL;
2984 // keep trying different suffix groups (posx, px, rt) until one loads
2985 for (j = 0;j < 3 && !cubemappixels;j++)
2987 // load the 6 images in the suffix group
2988 for (i = 0;i < 6;i++)
2990 // generate an image name based on the base and and suffix
2991 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2993 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2995 // an image loaded, make sure width and height are equal
2996 if (image_width == image_height)
2998 // if this is the first image to load successfully, allocate the cubemap memory
2999 if (!cubemappixels && image_width >= 1)
3001 cubemapsize = image_width;
3002 // note this clears to black, so unavailable sides are black
3003 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3005 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3007 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);
3010 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3012 Mem_Free(image_rgba);
3016 // if a cubemap loaded, upload it
3019 if (!r_shadow_filters_texturepool)
3020 r_shadow_filters_texturepool = R_AllocTexturePool();
3021 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3022 Mem_Free(cubemappixels);
3026 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3027 for (j = 0;j < 3;j++)
3028 for (i = 0;i < 6;i++)
3029 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3030 Con_Print(" and was unable to find any of them.\n");
3032 return cubemaptexture;
3035 rtexture_t *R_Shadow_Cubemap(const char *basename)
3038 for (i = 0;i < numcubemaps;i++)
3039 if (!strcasecmp(cubemaps[i].basename, basename))
3040 return cubemaps[i].texture;
3041 if (i >= MAX_CUBEMAPS)
3042 return r_texture_whitecube;
3044 strcpy(cubemaps[i].basename, basename);
3045 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3046 if (!cubemaps[i].texture)
3047 cubemaps[i].texture = r_texture_whitecube;
3048 return cubemaps[i].texture;
3051 void R_Shadow_FreeCubemaps(void)
3054 R_FreeTexturePool(&r_shadow_filters_texturepool);
3057 dlight_t *R_Shadow_NewWorldLight(void)
3060 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3061 light->next = r_shadow_worldlightchain;
3062 r_shadow_worldlightchain = light;
3066 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)
3068 VectorCopy(origin, light->origin);
3069 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3070 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3071 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3072 light->color[0] = max(color[0], 0);
3073 light->color[1] = max(color[1], 0);
3074 light->color[2] = max(color[2], 0);
3075 light->radius = max(radius, 0);
3076 light->style = style;
3077 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3079 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3082 light->shadow = shadowenable;
3083 light->corona = corona;
3086 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3087 light->coronasizescale = coronasizescale;
3088 light->ambientscale = ambientscale;
3089 light->diffusescale = diffusescale;
3090 light->specularscale = specularscale;
3091 light->flags = flags;
3092 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3094 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3097 void R_Shadow_FreeWorldLight(dlight_t *light)
3099 dlight_t **lightpointer;
3100 R_RTLight_Uncompile(&light->rtlight);
3101 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3102 if (*lightpointer != light)
3103 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3104 *lightpointer = light->next;
3108 void R_Shadow_ClearWorldLights(void)
3110 while (r_shadow_worldlightchain)
3111 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3112 r_shadow_selectedlight = NULL;
3113 R_Shadow_FreeCubemaps();
3116 void R_Shadow_SelectLight(dlight_t *light)
3118 if (r_shadow_selectedlight)
3119 r_shadow_selectedlight->selected = false;
3120 r_shadow_selectedlight = light;
3121 if (r_shadow_selectedlight)
3122 r_shadow_selectedlight->selected = true;
3125 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3127 float scale = r_editlights_cursorgrid.value * 0.5f;
3128 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);
3131 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3134 const dlight_t *light;
3137 if (light->selected)
3138 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3141 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);
3144 void R_Shadow_DrawLightSprites(void)
3150 for (i = 0;i < 5;i++)
3152 lighttextures[i] = NULL;
3153 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3154 lighttextures[i] = pic->tex;
3157 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3158 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3159 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3162 void R_Shadow_SelectLightInView(void)
3164 float bestrating, rating, temp[3];
3165 dlight_t *best, *light;
3168 for (light = r_shadow_worldlightchain;light;light = light->next)
3170 VectorSubtract(light->origin, r_vieworigin, temp);
3171 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3174 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3175 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3177 bestrating = rating;
3182 R_Shadow_SelectLight(best);
3185 void R_Shadow_LoadWorldLights(void)
3187 int n, a, style, shadow, flags;
3188 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3189 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3190 if (r_refdef.worldmodel == NULL)
3192 Con_Print("No map loaded.\n");
3195 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3196 strlcat (name, ".rtlights", sizeof (name));
3197 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3207 for (;COM_Parse(t, true) && strcmp(
3208 if (COM_Parse(t, true))
3210 if (com_token[0] == '!')
3213 origin[0] = atof(com_token+1);
3216 origin[0] = atof(com_token);
3221 while (*s && *s != '\n' && *s != '\r')
3227 // check for modifier flags
3234 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);
3237 flags = LIGHTFLAG_REALTIMEMODE;
3245 coronasizescale = 0.25f;
3247 VectorClear(angles);
3250 if (a < 9 || !strcmp(cubemapname, "\"\""))
3252 // remove quotes on cubemapname
3253 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3255 cubemapname[strlen(cubemapname)-1] = 0;
3256 strcpy(cubemapname, cubemapname + 1);
3260 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);
3263 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3271 Con_Printf("invalid rtlights file \"%s\"\n", name);
3272 Mem_Free(lightsstring);
3276 void R_Shadow_SaveWorldLights(void)
3279 size_t bufchars, bufmaxchars;
3281 char name[MAX_QPATH];
3283 if (!r_shadow_worldlightchain)
3285 if (r_refdef.worldmodel == NULL)
3287 Con_Print("No map loaded.\n");
3290 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3291 strlcat (name, ".rtlights", sizeof (name));
3292 bufchars = bufmaxchars = 0;
3294 for (light = r_shadow_worldlightchain;light;light = light->next)
3296 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3297 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);
3298 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3299 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]);
3301 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);
3302 if (bufchars + strlen(line) > bufmaxchars)
3304 bufmaxchars = bufchars + strlen(line) + 2048;
3306 buf = Mem_Alloc(tempmempool, bufmaxchars);
3310 memcpy(buf, oldbuf, bufchars);
3316 memcpy(buf + bufchars, line, strlen(line));
3317 bufchars += strlen(line);
3321 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3326 void R_Shadow_LoadLightsFile(void)
3329 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3330 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3331 if (r_refdef.worldmodel == NULL)
3333 Con_Print("No map loaded.\n");
3336 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3337 strlcat (name, ".lights", sizeof (name));
3338 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3346 while (*s && *s != '\n' && *s != '\r')
3352 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);
3356 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);
3359 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3360 radius = bound(15, radius, 4096);
3361 VectorScale(color, (2.0f / (8388608.0f)), color);
3362 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3370 Con_Printf("invalid lights file \"%s\"\n", name);
3371 Mem_Free(lightsstring);
3375 // tyrlite/hmap2 light types in the delay field
3376 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3378 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3380 int entnum, style, islight, skin, pflags, effects, type, n;
3383 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3384 char key[256], value[1024];
3386 if (r_refdef.worldmodel == NULL)
3388 Con_Print("No map loaded.\n");
3391 // try to load a .ent file first
3392 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3393 strlcat (key, ".ent", sizeof (key));
3394 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true);
3395 // and if that is not found, fall back to the bsp file entity string
3397 data = r_refdef.worldmodel->brush.entities;
3400 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3402 type = LIGHTTYPE_MINUSX;
3403 origin[0] = origin[1] = origin[2] = 0;
3404 originhack[0] = originhack[1] = originhack[2] = 0;
3405 angles[0] = angles[1] = angles[2] = 0;
3406 color[0] = color[1] = color[2] = 1;
3407 light[0] = light[1] = light[2] = 1;light[3] = 300;
3408 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3418 if (!COM_ParseToken(&data, false))
3420 if (com_token[0] == '}')
3421 break; // end of entity
3422 if (com_token[0] == '_')
3423 strcpy(key, com_token + 1);
3425 strcpy(key, com_token);
3426 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3427 key[strlen(key)-1] = 0;
3428 if (!COM_ParseToken(&data, false))
3430 strcpy(value, com_token);
3432 // now that we have the key pair worked out...
3433 if (!strcmp("light", key))
3435 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3439 light[0] = vec[0] * (1.0f / 256.0f);
3440 light[1] = vec[0] * (1.0f / 256.0f);
3441 light[2] = vec[0] * (1.0f / 256.0f);
3447 light[0] = vec[0] * (1.0f / 255.0f);
3448 light[1] = vec[1] * (1.0f / 255.0f);
3449 light[2] = vec[2] * (1.0f / 255.0f);
3453 else if (!strcmp("delay", key))
3455 else if (!strcmp("origin", key))
3456 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3457 else if (!strcmp("angle", key))
3458 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3459 else if (!strcmp("angles", key))
3460 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3461 else if (!strcmp("color", key))
3462 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3463 else if (!strcmp("wait", key))
3464 fadescale = atof(value);
3465 else if (!strcmp("classname", key))
3467 if (!strncmp(value, "light", 5))
3470 if (!strcmp(value, "light_fluoro"))
3475 overridecolor[0] = 1;
3476 overridecolor[1] = 1;
3477 overridecolor[2] = 1;
3479 if (!strcmp(value, "light_fluorospark"))
3484 overridecolor[0] = 1;
3485 overridecolor[1] = 1;
3486 overridecolor[2] = 1;
3488 if (!strcmp(value, "light_globe"))
3493 overridecolor[0] = 1;
3494 overridecolor[1] = 0.8;
3495 overridecolor[2] = 0.4;
3497 if (!strcmp(value, "light_flame_large_yellow"))
3502 overridecolor[0] = 1;
3503 overridecolor[1] = 0.5;
3504 overridecolor[2] = 0.1;
3506 if (!strcmp(value, "light_flame_small_yellow"))
3511 overridecolor[0] = 1;
3512 overridecolor[1] = 0.5;
3513 overridecolor[2] = 0.1;
3515 if (!strcmp(value, "light_torch_small_white"))
3520 overridecolor[0] = 1;
3521 overridecolor[1] = 0.5;
3522 overridecolor[2] = 0.1;
3524 if (!strcmp(value, "light_torch_small_walltorch"))
3529 overridecolor[0] = 1;
3530 overridecolor[1] = 0.5;
3531 overridecolor[2] = 0.1;
3535 else if (!strcmp("style", key))
3536 style = atoi(value);
3537 else if (!strcmp("skin", key))
3538 skin = (int)atof(value);
3539 else if (!strcmp("pflags", key))
3540 pflags = (int)atof(value);
3541 else if (!strcmp("effects", key))
3542 effects = (int)atof(value);
3543 else if (r_refdef.worldmodel->type == mod_brushq3)
3545 if (!strcmp("scale", key))
3546 lightscale = atof(value);
3547 if (!strcmp("fade", key))
3548 fadescale = atof(value);
3553 if (lightscale <= 0)
3557 if (color[0] == color[1] && color[0] == color[2])
3559 color[0] *= overridecolor[0];
3560 color[1] *= overridecolor[1];
3561 color[2] *= overridecolor[2];
3563 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3564 color[0] = color[0] * light[0];
3565 color[1] = color[1] * light[1];
3566 color[2] = color[2] * light[2];
3569 case LIGHTTYPE_MINUSX:
3571 case LIGHTTYPE_RECIPX:
3573 VectorScale(color, (1.0f / 16.0f), color);
3575 case LIGHTTYPE_RECIPXX:
3577 VectorScale(color, (1.0f / 16.0f), color);
3580 case LIGHTTYPE_NONE:
3584 case LIGHTTYPE_MINUSXX:
3587 VectorAdd(origin, originhack, origin);
3589 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);
3592 Mem_Free(entfiledata);
3596 void R_Shadow_SetCursorLocationForView(void)
3599 vec3_t dest, endpos;
3601 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3602 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3603 if (trace.fraction < 1)
3605 dist = trace.fraction * r_editlights_cursordistance.value;
3606 push = r_editlights_cursorpushback.value;
3610 VectorMA(trace.endpos, push, r_viewforward, endpos);
3611 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3615 VectorClear( endpos );
3617 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3618 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3619 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3622 void R_Shadow_UpdateWorldLightSelection(void)
3624 if (r_editlights.integer)
3626 R_Shadow_SetCursorLocationForView();
3627 R_Shadow_SelectLightInView();
3628 R_Shadow_DrawLightSprites();
3631 R_Shadow_SelectLight(NULL);
3634 void R_Shadow_EditLights_Clear_f(void)
3636 R_Shadow_ClearWorldLights();
3639 void R_Shadow_EditLights_Reload_f(void)
3641 if (!r_refdef.worldmodel)
3643 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3644 R_Shadow_ClearWorldLights();
3645 R_Shadow_LoadWorldLights();
3646 if (r_shadow_worldlightchain == NULL)
3648 R_Shadow_LoadLightsFile();
3649 if (r_shadow_worldlightchain == NULL)
3650 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3654 void R_Shadow_EditLights_Save_f(void)
3656 if (!r_refdef.worldmodel)
3658 R_Shadow_SaveWorldLights();
3661 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3663 R_Shadow_ClearWorldLights();
3664 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3667 void R_Shadow_EditLights_ImportLightsFile_f(void)
3669 R_Shadow_ClearWorldLights();
3670 R_Shadow_LoadLightsFile();
3673 void R_Shadow_EditLights_Spawn_f(void)
3676 if (!r_editlights.integer)
3678 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3681 if (Cmd_Argc() != 1)
3683 Con_Print("r_editlights_spawn does not take parameters\n");
3686 color[0] = color[1] = color[2] = 1;
3687 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3690 void R_Shadow_EditLights_Edit_f(void)
3692 vec3_t origin, angles, color;
3693 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3694 int style, shadows, flags, normalmode, realtimemode;
3695 char cubemapname[1024];
3696 if (!r_editlights.integer)
3698 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3701 if (!r_shadow_selectedlight)
3703 Con_Print("No selected light.\n");
3706 VectorCopy(r_shadow_selectedlight->origin, origin);
3707 VectorCopy(r_shadow_selectedlight->angles, angles);
3708 VectorCopy(r_shadow_selectedlight->color, color);
3709 radius = r_shadow_selectedlight->radius;
3710 style = r_shadow_selectedlight->style;
3711 if (r_shadow_selectedlight->cubemapname)
3712 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3715 shadows = r_shadow_selectedlight->shadow;
3716 corona = r_shadow_selectedlight->corona;
3717 coronasizescale = r_shadow_selectedlight->coronasizescale;
3718 ambientscale = r_shadow_selectedlight->ambientscale;
3719 diffusescale = r_shadow_selectedlight->diffusescale;
3720 specularscale = r_shadow_selectedlight->specularscale;
3721 flags = r_shadow_selectedlight->flags;
3722 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3723 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3724 if (!strcmp(Cmd_Argv(1), "origin"))
3726 if (Cmd_Argc() != 5)
3728 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3731 origin[0] = atof(Cmd_Argv(2));
3732 origin[1] = atof(Cmd_Argv(3));
3733 origin[2] = atof(Cmd_Argv(4));
3735 else if (!strcmp(Cmd_Argv(1), "originx"))
3737 if (Cmd_Argc() != 3)
3739 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3742 origin[0] = atof(Cmd_Argv(2));
3744 else if (!strcmp(Cmd_Argv(1), "originy"))
3746 if (Cmd_Argc() != 3)
3748 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3751 origin[1] = atof(Cmd_Argv(2));
3753 else if (!strcmp(Cmd_Argv(1), "originz"))
3755 if (Cmd_Argc() != 3)
3757 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3760 origin[2] = atof(Cmd_Argv(2));
3762 else if (!strcmp(Cmd_Argv(1), "move"))
3764 if (Cmd_Argc() != 5)
3766 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3769 origin[0] += atof(Cmd_Argv(2));
3770 origin[1] += atof(Cmd_Argv(3));
3771 origin[2] += atof(Cmd_Argv(4));
3773 else if (!strcmp(Cmd_Argv(1), "movex"))
3775 if (Cmd_Argc() != 3)
3777 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3780 origin[0] += atof(Cmd_Argv(2));
3782 else if (!strcmp(Cmd_Argv(1), "movey"))
3784 if (Cmd_Argc() != 3)
3786 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3789 origin[1] += atof(Cmd_Argv(2));
3791 else if (!strcmp(Cmd_Argv(1), "movez"))
3793 if (Cmd_Argc() != 3)
3795 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3798 origin[2] += atof(Cmd_Argv(2));
3800 else if (!strcmp(Cmd_Argv(1), "angles"))
3802 if (Cmd_Argc() != 5)
3804 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3807 angles[0] = atof(Cmd_Argv(2));
3808 angles[1] = atof(Cmd_Argv(3));
3809 angles[2] = atof(Cmd_Argv(4));
3811 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3813 if (Cmd_Argc() != 3)
3815 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3818 angles[0] = atof(Cmd_Argv(2));
3820 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3822 if (Cmd_Argc() != 3)
3824 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3827 angles[1] = atof(Cmd_Argv(2));
3829 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3831 if (Cmd_Argc() != 3)
3833 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3836 angles[2] = atof(Cmd_Argv(2));
3838 else if (!strcmp(Cmd_Argv(1), "color"))
3840 if (Cmd_Argc() != 5)
3842 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3845 color[0] = atof(Cmd_Argv(2));
3846 color[1] = atof(Cmd_Argv(3));
3847 color[2] = atof(Cmd_Argv(4));
3849 else if (!strcmp(Cmd_Argv(1), "radius"))
3851 if (Cmd_Argc() != 3)
3853 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3856 radius = atof(Cmd_Argv(2));
3858 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3860 if (Cmd_Argc() == 3)
3862 double scale = atof(Cmd_Argv(2));
3869 if (Cmd_Argc() != 5)
3871 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3874 color[0] *= atof(Cmd_Argv(2));
3875 color[1] *= atof(Cmd_Argv(3));
3876 color[2] *= atof(Cmd_Argv(4));
3879 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3881 if (Cmd_Argc() != 3)
3883 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3886 radius *= atof(Cmd_Argv(2));
3888 else if (!strcmp(Cmd_Argv(1), "style"))
3890 if (Cmd_Argc() != 3)
3892 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3895 style = atoi(Cmd_Argv(2));
3897 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3901 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3904 if (Cmd_Argc() == 3)
3905 strcpy(cubemapname, Cmd_Argv(2));
3909 else if (!strcmp(Cmd_Argv(1), "shadows"))
3911 if (Cmd_Argc() != 3)
3913 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3916 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3918 else if (!strcmp(Cmd_Argv(1), "corona"))
3920 if (Cmd_Argc() != 3)
3922 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3925 corona = atof(Cmd_Argv(2));
3927 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3929 if (Cmd_Argc() != 3)
3931 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3934 coronasizescale = atof(Cmd_Argv(2));
3936 else if (!strcmp(Cmd_Argv(1), "ambient"))
3938 if (Cmd_Argc() != 3)
3940 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3943 ambientscale = atof(Cmd_Argv(2));
3945 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3947 if (Cmd_Argc() != 3)
3949 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3952 diffusescale = atof(Cmd_Argv(2));
3954 else if (!strcmp(Cmd_Argv(1), "specular"))
3956 if (Cmd_Argc() != 3)
3958 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3961 specularscale = atof(Cmd_Argv(2));
3963 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3965 if (Cmd_Argc() != 3)
3967 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3970 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3972 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3974 if (Cmd_Argc() != 3)
3976 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3979 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3983 Con_Print("usage: r_editlights_edit [property] [value]\n");
3984 Con_Print("Selected light's properties:\n");
3985 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3986 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3987 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3988 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3989 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3990 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3991 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3992 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3993 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3994 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3995 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3996 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3997 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3998 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4001 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4002 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4005 void R_Shadow_EditLights_EditAll_f(void)
4009 if (!r_editlights.integer)
4011 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4015 for (light = r_shadow_worldlightchain;light;light = light->next)
4017 R_Shadow_SelectLight(light);
4018 R_Shadow_EditLights_Edit_f();
4022 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4024 int lightnumber, lightcount;
4028 if (!r_editlights.integer)
4034 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4035 if (light == r_shadow_selectedlight)
4036 lightnumber = lightcount;
4037 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;
4038 if (r_shadow_selectedlight == NULL)
4040 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4041 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;
4042 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;
4043 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;
4044 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4045 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4046 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4047 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;
4048 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4049 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4050 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4051 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4052 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4053 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;
4054 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;
4057 void R_Shadow_EditLights_ToggleShadow_f(void)
4059 if (!r_editlights.integer)
4061 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4064 if (!r_shadow_selectedlight)
4066 Con_Print("No selected light.\n");
4069 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);
4072 void R_Shadow_EditLights_ToggleCorona_f(void)
4074 if (!r_editlights.integer)
4076 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4079 if (!r_shadow_selectedlight)
4081 Con_Print("No selected light.\n");
4084 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);
4087 void R_Shadow_EditLights_Remove_f(void)
4089 if (!r_editlights.integer)
4091 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4094 if (!r_shadow_selectedlight)
4096 Con_Print("No selected light.\n");
4099 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4100 r_shadow_selectedlight = NULL;
4103 void R_Shadow_EditLights_Help_f(void)
4106 "Documentation on r_editlights system:\n"
4108 "r_editlights : enable/disable editing mode\n"
4109 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4110 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4111 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4112 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4113 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4115 "r_editlights_help : this help\n"
4116 "r_editlights_clear : remove all lights\n"
4117 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4118 "r_editlights_save : save to .rtlights file\n"
4119 "r_editlights_spawn : create a light with default settings\n"
4120 "r_editlights_edit command : edit selected light - more documentation below\n"
4121 "r_editlights_remove : remove selected light\n"
4122 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4123 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4124 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4126 "origin x y z : set light location\n"
4127 "originx x: set x component of light location\n"
4128 "originy y: set y component of light location\n"
4129 "originz z: set z component of light location\n"
4130 "move x y z : adjust light location\n"
4131 "movex x: adjust x component of light location\n"
4132 "movey y: adjust y component of light location\n"
4133 "movez z: adjust z component of light location\n"
4134 "angles x y z : set light angles\n"
4135 "anglesx x: set x component of light angles\n"
4136 "anglesy y: set y component of light angles\n"
4137 "anglesz z: set z component of light angles\n"
4138 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4139 "radius radius : set radius (size) of light\n"
4140 "colorscale grey : multiply color of light (1 does nothing)\n"
4141 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4142 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4143 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4144 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4145 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4146 "shadows 1/0 : turn on/off shadows\n"
4147 "corona n : set corona intensity\n"
4148 "coronasize n : set corona size (0-1)\n"
4149 "ambient n : set ambient intensity (0-1)\n"
4150 "diffuse n : set diffuse intensity (0-1)\n"
4151 "specular n : set specular intensity (0-1)\n"
4152 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4153 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4154 "<nothing> : print light properties to console\n"
4158 void R_Shadow_EditLights_CopyInfo_f(void)
4160 if (!r_editlights.integer)
4162 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4165 if (!r_shadow_selectedlight)
4167 Con_Print("No selected light.\n");
4170 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4171 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4172 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4173 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4174 if (r_shadow_selectedlight->cubemapname)
4175 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4177 r_shadow_bufferlight.cubemapname[0] = 0;
4178 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4179 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4180 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4181 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4182 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4183 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4184 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4187 void R_Shadow_EditLights_PasteInfo_f(void)
4189 if (!r_editlights.integer)
4191 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4194 if (!r_shadow_selectedlight)
4196 Con_Print("No selected light.\n");
4199 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);
4202 void R_Shadow_EditLights_Init(void)
4204 Cvar_RegisterVariable(&r_editlights);
4205 Cvar_RegisterVariable(&r_editlights_cursordistance);
4206 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4207 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4208 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4209 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4210 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4211 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4212 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4213 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4214 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4215 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4216 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4217 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4218 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4219 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4220 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4221 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4222 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4223 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);