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_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_STENCIL,
149 R_SHADOW_RENDERMODE_STENCILTWOSIDE,
150 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
151 R_SHADOW_RENDERMODE_LIGHT_DOT3,
152 R_SHADOW_RENDERMODE_LIGHT_GLSL,
153 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
154 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
156 r_shadow_rendermode_t;
158 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
159 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
162 mempool_t *r_shadow_mempool;
164 int maxshadowelements;
178 int r_shadow_buffer_numleafpvsbytes;
179 unsigned char *r_shadow_buffer_leafpvs;
180 int *r_shadow_buffer_leaflist;
182 int r_shadow_buffer_numsurfacepvsbytes;
183 unsigned char *r_shadow_buffer_surfacepvs;
184 int *r_shadow_buffer_surfacelist;
186 rtexturepool_t *r_shadow_texturepool;
187 rtexture_t *r_shadow_attenuation2dtexture;
188 rtexture_t *r_shadow_attenuation3dtexture;
190 // lights are reloaded when this changes
191 char r_shadow_mapname[MAX_QPATH];
193 // used only for light filters (cubemaps)
194 rtexturepool_t *r_shadow_filters_texturepool;
196 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
197 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
198 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
199 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
200 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
201 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
202 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
203 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
204 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
205 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
206 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
207 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
208 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
209 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
210 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
211 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
212 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
213 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
214 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
215 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
216 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
217 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
218 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
219 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
220 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
221 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
222 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
223 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
224 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "0"};
225 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
226 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
227 cvar_t r_shadow_glsl_usehalffloat = {0, "r_shadow_glsl_usehalffloat", "0"};
228 cvar_t r_shadow_glsl_surfacenormalize = {0, "r_shadow_glsl_surfacenormalize", "1"};
229 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
230 cvar_t r_editlights = {0, "r_editlights", "0"};
231 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
232 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
233 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
234 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
235 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
237 float r_shadow_attenpower, r_shadow_attenscale;
239 rtlight_t *r_shadow_compilingrtlight;
240 dlight_t *r_shadow_worldlightchain;
241 dlight_t *r_shadow_selectedlight;
242 dlight_t r_shadow_bufferlight;
243 vec3_t r_editlights_cursorlocation;
245 rtexture_t *lighttextures[5];
247 extern int con_vislines;
249 typedef struct cubemapinfo_s
256 #define MAX_CUBEMAPS 256
257 static int numcubemaps;
258 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
260 #define SHADERPERMUTATION_SPECULAR (1<<0)
261 #define SHADERPERMUTATION_FOG (1<<1)
262 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
263 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
264 #define SHADERPERMUTATION_SURFACENORMALIZE (1<<4)
265 #define SHADERPERMUTATION_GEFORCEFX (1<<5)
266 #define SHADERPERMUTATION_COUNT (1<<6)
268 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
270 void R_Shadow_UncompileWorldLights(void);
271 void R_Shadow_ClearWorldLights(void);
272 void R_Shadow_SaveWorldLights(void);
273 void R_Shadow_LoadWorldLights(void);
274 void R_Shadow_LoadLightsFile(void);
275 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
276 void R_Shadow_EditLights_Reload_f(void);
277 void R_Shadow_ValidateCvars(void);
278 static void R_Shadow_MakeTextures(void);
279 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
281 const char *builtinshader_light_vert =
282 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
283 "// written by Forest 'LordHavoc' Hale\n"
285 "// use half floats if available for math performance\n"
287 "#define myhalf half\n"
288 "#define myhvec2 hvec2\n"
289 "#define myhvec3 hvec3\n"
290 "#define myhvec4 hvec4\n"
292 "#define myhalf float\n"
293 "#define myhvec2 vec2\n"
294 "#define myhvec3 vec3\n"
295 "#define myhvec4 vec4\n"
298 "uniform vec3 LightPosition;\n"
300 "varying vec2 TexCoord;\n"
301 "varying myhvec3 CubeVector;\n"
302 "varying vec3 LightVector;\n"
304 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
305 "uniform vec3 EyePosition;\n"
306 "varying vec3 EyeVector;\n"
309 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
313 " // copy the surface texcoord\n"
314 " TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
316 " // transform vertex position into light attenuation/cubemap space\n"
317 " // (-1 to +1 across the light box)\n"
318 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
320 " // transform unnormalized light direction into tangent space\n"
321 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
322 " // normalize it per pixel)\n"
323 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
324 " LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
325 " LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
326 " LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
328 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
329 " // transform unnormalized eye direction into tangent space\n"
330 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
331 " EyeVector.x = dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
332 " EyeVector.y = dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
333 " EyeVector.z = dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
336 " // transform vertex to camera space, using ftransform to match non-VS\n"
338 " gl_Position = ftransform();\n"
342 const char *builtinshader_light_frag =
343 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
344 "// written by Forest 'LordHavoc' Hale\n"
346 "// use half floats if available for math performance\n"
348 "#define myhalf half\n"
349 "#define myhvec2 hvec2\n"
350 "#define myhvec3 hvec3\n"
351 "#define myhvec4 hvec4\n"
353 "#define myhalf float\n"
354 "#define myhvec2 vec2\n"
355 "#define myhvec3 vec3\n"
356 "#define myhvec4 vec4\n"
359 "uniform myhvec3 LightColor;\n"
360 "#ifdef USEOFFSETMAPPING\n"
361 "uniform myhalf OffsetMapping_Scale;\n"
362 "uniform myhalf OffsetMapping_Bias;\n"
364 "#ifdef USESPECULAR\n"
365 "uniform myhalf SpecularPower;\n"
368 "uniform myhalf FogRangeRecip;\n"
370 "uniform myhalf AmbientScale;\n"
371 "uniform myhalf DiffuseScale;\n"
372 "#ifdef USESPECULAR\n"
373 "uniform myhalf SpecularScale;\n"
376 "uniform sampler2D Texture_Normal;\n"
377 "uniform sampler2D Texture_Color;\n"
378 "#ifdef USESPECULAR\n"
379 "uniform sampler2D Texture_Gloss;\n"
381 "#ifdef USECUBEFILTER\n"
382 "uniform samplerCube Texture_Cube;\n"
385 "uniform sampler2D Texture_FogMask;\n"
388 "varying vec2 TexCoord;\n"
389 "varying myhvec3 CubeVector;\n"
390 "varying vec3 LightVector;\n"
391 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
392 "varying vec3 EyeVector;\n"
399 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
400 " // center and sharp falloff at the edge, this is about the most efficient\n"
401 " // we can get away with as far as providing illumination.\n"
403 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
404 " // provide significant illumination, large = slow = pain.\n"
405 " myhalf colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
409 " colorscale *= texture2D(Texture_FogMask, myhvec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
412 "#ifdef USEOFFSETMAPPING\n"
413 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
414 " myhvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
415 " myhvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
416 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
417 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
418 "#define TexCoord TexCoordOffset\n"
421 " // get the surface normal\n"
422 "#ifdef SURFACENORMALIZE\n"
423 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
425 " myhvec3 surfacenormal = -1.0 + 2.0 * myhvec3(texture2D(Texture_Normal, TexCoord));\n"
428 " // calculate shading\n"
429 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
430 " myhvec3 color = myhvec3(texture2D(Texture_Color, TexCoord)) * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
431 "#ifdef USESPECULAR\n"
432 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
433 " color += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
436 "#ifdef USECUBEFILTER\n"
437 " // apply light cubemap filter\n"
438 " color *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
441 " // calculate fragment color (apply light color and attenuation/fog scaling)\n"
442 " gl_FragColor = myhvec4(color * LightColor * colorscale, 1);\n"
446 void r_shadow_start(void)
449 // use half float math where available (speed gain on NVIDIA GFFX and GF6)
450 if (gl_support_half_float)
451 Cvar_SetValue("r_shadow_glsl_usehalffloat", 1);
452 // allocate vertex processing arrays
454 r_shadow_attenuation2dtexture = NULL;
455 r_shadow_attenuation3dtexture = NULL;
456 r_shadow_texturepool = NULL;
457 r_shadow_filters_texturepool = NULL;
458 R_Shadow_ValidateCvars();
459 R_Shadow_MakeTextures();
460 maxshadowelements = 0;
461 shadowelements = NULL;
469 shadowmarklist = NULL;
471 r_shadow_buffer_numleafpvsbytes = 0;
472 r_shadow_buffer_leafpvs = NULL;
473 r_shadow_buffer_leaflist = NULL;
474 r_shadow_buffer_numsurfacepvsbytes = 0;
475 r_shadow_buffer_surfacepvs = NULL;
476 r_shadow_buffer_surfacelist = NULL;
477 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
478 r_shadow_program_light[i] = 0;
479 if (gl_support_fragment_shader)
481 char *vertstring, *fragstring;
482 int vertstrings_count;
483 int fragstrings_count;
484 const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
485 const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
486 vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false, NULL);
487 fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false, NULL);
488 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
490 vertstrings_count = 0;
491 fragstrings_count = 0;
492 if (i & SHADERPERMUTATION_SPECULAR)
494 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
495 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
497 if (i & SHADERPERMUTATION_FOG)
499 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
500 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
502 if (i & SHADERPERMUTATION_CUBEFILTER)
504 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
505 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
507 if (i & SHADERPERMUTATION_OFFSETMAPPING)
509 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
510 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
512 if (i & SHADERPERMUTATION_SURFACENORMALIZE)
514 vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
515 fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
517 if (i & SHADERPERMUTATION_GEFORCEFX)
519 // if the extension does not exist, don't try to compile it
520 if (!gl_support_half_float)
522 vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
523 fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
525 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
526 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
527 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
528 if (!r_shadow_program_light[i])
530 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");
533 qglUseProgramObjectARB(r_shadow_program_light[i]);
534 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
535 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
536 if (i & SHADERPERMUTATION_SPECULAR)
538 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
540 if (i & SHADERPERMUTATION_CUBEFILTER)
542 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
544 if (i & SHADERPERMUTATION_FOG)
546 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
549 qglUseProgramObjectARB(0);
551 Mem_Free(fragstring);
553 Mem_Free(vertstring);
557 void r_shadow_shutdown(void)
560 R_Shadow_UncompileWorldLights();
561 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
563 if (r_shadow_program_light[i])
565 GL_Backend_FreeProgram(r_shadow_program_light[i]);
566 r_shadow_program_light[i] = 0;
570 r_shadow_attenuation2dtexture = NULL;
571 r_shadow_attenuation3dtexture = NULL;
572 R_FreeTexturePool(&r_shadow_texturepool);
573 R_FreeTexturePool(&r_shadow_filters_texturepool);
574 maxshadowelements = 0;
576 Mem_Free(shadowelements);
577 shadowelements = NULL;
580 Mem_Free(vertexupdate);
583 Mem_Free(vertexremap);
589 Mem_Free(shadowmark);
592 Mem_Free(shadowmarklist);
593 shadowmarklist = NULL;
595 r_shadow_buffer_numleafpvsbytes = 0;
596 if (r_shadow_buffer_leafpvs)
597 Mem_Free(r_shadow_buffer_leafpvs);
598 r_shadow_buffer_leafpvs = NULL;
599 if (r_shadow_buffer_leaflist)
600 Mem_Free(r_shadow_buffer_leaflist);
601 r_shadow_buffer_leaflist = NULL;
602 r_shadow_buffer_numsurfacepvsbytes = 0;
603 if (r_shadow_buffer_surfacepvs)
604 Mem_Free(r_shadow_buffer_surfacepvs);
605 r_shadow_buffer_surfacepvs = NULL;
606 if (r_shadow_buffer_surfacelist)
607 Mem_Free(r_shadow_buffer_surfacelist);
608 r_shadow_buffer_surfacelist = NULL;
611 void r_shadow_newmap(void)
615 void R_Shadow_Help_f(void)
618 "Documentation on r_shadow system:\n"
620 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
621 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
622 "r_shadow_debuglight : render only this light number (-1 = all)\n"
623 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
624 "r_shadow_gloss2intensity : brightness of forced gloss\n"
625 "r_shadow_glossintensity : brightness of textured gloss\n"
626 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
627 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
628 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
629 "r_shadow_portallight : use portal visibility for static light precomputation\n"
630 "r_shadow_projectdistance : shadow volume projection distance\n"
631 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
632 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
633 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
634 "r_shadow_realtime_world : use high quality world lighting mode\n"
635 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
636 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
637 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
638 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
639 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
640 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
641 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
642 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
643 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
644 "r_shadow_glsl_usehalffloat : use lower quality lighting\n"
645 "r_shadow_glsl_surfacenormalize : makes bumpmapping slightly higher quality\n"
646 "r_shadow_scissor : use scissor optimization\n"
647 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
648 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
649 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
650 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
651 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
652 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
654 "r_shadow_help : this help\n"
658 void R_Shadow_Init(void)
660 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
661 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
662 Cvar_RegisterVariable(&r_shadow_debuglight);
663 Cvar_RegisterVariable(&r_shadow_gloss);
664 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
665 Cvar_RegisterVariable(&r_shadow_glossintensity);
666 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
667 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
668 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
669 Cvar_RegisterVariable(&r_shadow_portallight);
670 Cvar_RegisterVariable(&r_shadow_projectdistance);
671 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
672 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
673 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
674 Cvar_RegisterVariable(&r_shadow_realtime_world);
675 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
676 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
677 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
678 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
679 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
680 Cvar_RegisterVariable(&r_shadow_scissor);
681 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
682 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
683 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
684 Cvar_RegisterVariable(&r_shadow_texture3d);
685 Cvar_RegisterVariable(&r_shadow_visiblelighting);
686 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
687 Cvar_RegisterVariable(&r_shadow_glsl);
688 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
689 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
690 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
691 Cvar_RegisterVariable(&r_shadow_glsl_usehalffloat);
692 Cvar_RegisterVariable(&r_shadow_glsl_surfacenormalize);
693 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
694 if (gamemode == GAME_TENEBRAE)
696 Cvar_SetValue("r_shadow_gloss", 2);
697 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
699 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
700 R_Shadow_EditLights_Init();
701 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
702 r_shadow_worldlightchain = NULL;
703 maxshadowelements = 0;
704 shadowelements = NULL;
712 shadowmarklist = NULL;
714 r_shadow_buffer_numleafpvsbytes = 0;
715 r_shadow_buffer_leafpvs = NULL;
716 r_shadow_buffer_leaflist = NULL;
717 r_shadow_buffer_numsurfacepvsbytes = 0;
718 r_shadow_buffer_surfacepvs = NULL;
719 r_shadow_buffer_surfacelist = NULL;
720 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
723 matrix4x4_t matrix_attenuationxyz =
726 {0.5, 0.0, 0.0, 0.5},
727 {0.0, 0.5, 0.0, 0.5},
728 {0.0, 0.0, 0.5, 0.5},
733 matrix4x4_t matrix_attenuationz =
736 {0.0, 0.0, 0.5, 0.5},
737 {0.0, 0.0, 0.0, 0.5},
738 {0.0, 0.0, 0.0, 0.5},
743 int *R_Shadow_ResizeShadowElements(int numtris)
745 // make sure shadowelements is big enough for this volume
746 if (maxshadowelements < numtris * 24)
748 maxshadowelements = numtris * 24;
750 Mem_Free(shadowelements);
751 shadowelements = (int *)Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
753 return shadowelements;
756 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
758 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
759 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
760 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
762 if (r_shadow_buffer_leafpvs)
763 Mem_Free(r_shadow_buffer_leafpvs);
764 if (r_shadow_buffer_leaflist)
765 Mem_Free(r_shadow_buffer_leaflist);
766 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
767 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
768 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
770 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
772 if (r_shadow_buffer_surfacepvs)
773 Mem_Free(r_shadow_buffer_surfacepvs);
774 if (r_shadow_buffer_surfacelist)
775 Mem_Free(r_shadow_buffer_surfacelist);
776 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
777 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
778 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
782 void R_Shadow_PrepareShadowMark(int numtris)
784 // make sure shadowmark is big enough for this volume
785 if (maxshadowmark < numtris)
787 maxshadowmark = numtris;
789 Mem_Free(shadowmark);
791 Mem_Free(shadowmarklist);
792 shadowmark = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
793 shadowmarklist = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
797 // if shadowmarkcount wrapped we clear the array and adjust accordingly
798 if (shadowmarkcount == 0)
801 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
806 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)
809 int outtriangles = 0, outvertices = 0;
813 if (maxvertexupdate < innumvertices)
815 maxvertexupdate = innumvertices;
817 Mem_Free(vertexupdate);
819 Mem_Free(vertexremap);
820 vertexupdate = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
821 vertexremap = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
825 if (vertexupdatenum == 0)
828 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
829 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
832 for (i = 0;i < numshadowmarktris;i++)
833 shadowmark[shadowmarktris[i]] = shadowmarkcount;
835 for (i = 0;i < numshadowmarktris;i++)
837 element = inelement3i + shadowmarktris[i] * 3;
838 // make sure the vertices are created
839 for (j = 0;j < 3;j++)
841 if (vertexupdate[element[j]] != vertexupdatenum)
843 float ratio, direction[3];
844 vertexupdate[element[j]] = vertexupdatenum;
845 vertexremap[element[j]] = outvertices;
846 vertex = invertex3f + element[j] * 3;
847 // project one copy of the vertex to the sphere radius of the light
848 // (FIXME: would projecting it to the light box be better?)
849 VectorSubtract(vertex, projectorigin, direction);
850 ratio = projectdistance / VectorLength(direction);
851 VectorCopy(vertex, outvertex3f);
852 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
859 for (i = 0;i < numshadowmarktris;i++)
861 int remappedelement[3];
863 const int *neighbortriangle;
865 markindex = shadowmarktris[i] * 3;
866 element = inelement3i + markindex;
867 neighbortriangle = inneighbor3i + markindex;
868 // output the front and back triangles
869 outelement3i[0] = vertexremap[element[0]];
870 outelement3i[1] = vertexremap[element[1]];
871 outelement3i[2] = vertexremap[element[2]];
872 outelement3i[3] = vertexremap[element[2]] + 1;
873 outelement3i[4] = vertexremap[element[1]] + 1;
874 outelement3i[5] = vertexremap[element[0]] + 1;
878 // output the sides (facing outward from this triangle)
879 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
881 remappedelement[0] = vertexremap[element[0]];
882 remappedelement[1] = vertexremap[element[1]];
883 outelement3i[0] = remappedelement[1];
884 outelement3i[1] = remappedelement[0];
885 outelement3i[2] = remappedelement[0] + 1;
886 outelement3i[3] = remappedelement[1];
887 outelement3i[4] = remappedelement[0] + 1;
888 outelement3i[5] = remappedelement[1] + 1;
893 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
895 remappedelement[1] = vertexremap[element[1]];
896 remappedelement[2] = vertexremap[element[2]];
897 outelement3i[0] = remappedelement[2];
898 outelement3i[1] = remappedelement[1];
899 outelement3i[2] = remappedelement[1] + 1;
900 outelement3i[3] = remappedelement[2];
901 outelement3i[4] = remappedelement[1] + 1;
902 outelement3i[5] = remappedelement[2] + 1;
907 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
909 remappedelement[0] = vertexremap[element[0]];
910 remappedelement[2] = vertexremap[element[2]];
911 outelement3i[0] = remappedelement[0];
912 outelement3i[1] = remappedelement[2];
913 outelement3i[2] = remappedelement[2] + 1;
914 outelement3i[3] = remappedelement[0];
915 outelement3i[4] = remappedelement[2] + 1;
916 outelement3i[5] = remappedelement[0] + 1;
923 *outnumvertices = outvertices;
927 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)
930 if (projectdistance < 0.1)
932 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
935 if (!numverts || !nummarktris)
937 // make sure shadowelements is big enough for this volume
938 if (maxshadowelements < nummarktris * 24)
939 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
940 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
941 renderstats.lights_dynamicshadowtriangles += tris;
942 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
945 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)
950 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
952 tend = firsttriangle + numtris;
953 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
954 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
955 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
957 // surface box entirely inside light box, no box cull
958 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
959 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
960 shadowmarklist[numshadowmark++] = t;
964 // surface box not entirely inside light box, cull each triangle
965 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
967 v[0] = invertex3f + e[0] * 3;
968 v[1] = invertex3f + e[1] * 3;
969 v[2] = invertex3f + e[2] * 3;
970 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
971 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
972 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
973 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
974 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
975 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
976 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
977 shadowmarklist[numshadowmark++] = t;
982 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
985 if (r_shadow_compilingrtlight)
987 // if we're compiling an rtlight, capture the mesh
988 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
991 renderstats.lights_shadowtriangles += numtriangles;
992 memset(&m, 0, sizeof(m));
993 m.pointer_vertex = vertex3f;
995 GL_LockArrays(0, numvertices);
996 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
998 // decrement stencil if backface is behind depthbuffer
999 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
1000 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1001 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
1002 // increment stencil if frontface is behind depthbuffer
1003 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1004 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1006 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
1007 GL_LockArrays(0, 0);
1010 static void R_Shadow_MakeTextures(void)
1013 float v[3], intensity;
1014 unsigned char *data;
1015 R_FreeTexturePool(&r_shadow_texturepool);
1016 r_shadow_texturepool = R_AllocTexturePool();
1017 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
1018 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
1019 #define ATTEN2DSIZE 64
1020 #define ATTEN3DSIZE 32
1021 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
1022 for (y = 0;y < ATTEN2DSIZE;y++)
1024 for (x = 0;x < ATTEN2DSIZE;x++)
1026 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1027 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1029 intensity = 1.0f - sqrt(DotProduct(v, v));
1031 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1032 d = bound(0, intensity, 255);
1033 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1034 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1035 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1036 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1039 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1040 if (r_shadow_texture3d.integer)
1042 for (z = 0;z < ATTEN3DSIZE;z++)
1044 for (y = 0;y < ATTEN3DSIZE;y++)
1046 for (x = 0;x < ATTEN3DSIZE;x++)
1048 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1049 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1050 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1051 intensity = 1.0f - sqrt(DotProduct(v, v));
1053 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1054 d = bound(0, intensity, 255);
1055 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1056 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1057 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1058 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1062 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1067 void R_Shadow_ValidateCvars(void)
1069 if (r_shadow_texture3d.integer && !gl_texture3d)
1070 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1071 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1072 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1075 // light currently being rendered
1076 rtlight_t *r_shadow_rtlight;
1078 // this is the location of the eye in entity space
1079 vec3_t r_shadow_entityeyeorigin;
1080 // this is the location of the light in entity space
1081 vec3_t r_shadow_entitylightorigin;
1082 // this transforms entity coordinates to light filter cubemap coordinates
1083 // (also often used for other purposes)
1084 matrix4x4_t r_shadow_entitytolight;
1085 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1086 // of attenuation texturing in full 3D (Z result often ignored)
1087 matrix4x4_t r_shadow_entitytoattenuationxyz;
1088 // this transforms only the Z to S, and T is always 0.5
1089 matrix4x4_t r_shadow_entitytoattenuationz;
1091 static int r_shadow_lightpermutation;
1092 static int r_shadow_lightprog;
1094 void R_Shadow_RenderMode_Begin(void)
1098 R_Shadow_ValidateCvars();
1100 if (!r_shadow_attenuation2dtexture
1101 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1102 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1103 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1104 R_Shadow_MakeTextures();
1106 memset(&m, 0, sizeof(m));
1108 GL_BlendFunc(GL_ONE, GL_ZERO);
1109 GL_DepthMask(false);
1111 GL_Color(0, 0, 0, 1);
1112 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1113 qglEnable(GL_CULL_FACE);
1114 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1116 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1118 if (gl_ext_stenciltwoside.integer)
1119 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1121 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1123 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1124 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1125 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1126 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1128 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1131 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1133 r_shadow_rtlight = rtlight;
1136 void R_Shadow_RenderMode_Reset(void)
1139 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1141 qglUseProgramObjectARB(0);
1142 // HACK HACK HACK: work around for bug in NVIDIAI 6xxx drivers that causes GL_OUT_OF_MEMORY and/or software rendering
1143 qglBegin(GL_TRIANGLES);
1147 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1148 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1149 memset(&m, 0, sizeof(m));
1153 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1155 R_Shadow_RenderMode_Reset();
1156 GL_Color(1, 1, 1, 1);
1157 GL_ColorMask(0, 0, 0, 0);
1158 GL_BlendFunc(GL_ONE, GL_ZERO);
1159 GL_DepthMask(false);
1161 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1162 //if (r_shadow_shadow_polygonoffset.value != 0)
1164 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1165 // qglEnable(GL_POLYGON_OFFSET_FILL);
1168 // qglDisable(GL_POLYGON_OFFSET_FILL);
1169 qglDepthFunc(GL_LESS);
1170 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1171 qglEnable(GL_STENCIL_TEST);
1172 qglStencilFunc(GL_ALWAYS, 128, ~0);
1173 r_shadow_rendermode = r_shadow_shadowingrendermode;
1174 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1176 qglDisable(GL_CULL_FACE);
1177 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1178 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1180 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1181 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1183 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1187 qglEnable(GL_CULL_FACE);
1189 // this is changed by every shadow render so its value here is unimportant
1190 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1192 GL_Clear(GL_STENCIL_BUFFER_BIT);
1193 renderstats.lights_clears++;
1196 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1198 R_Shadow_RenderMode_Reset();
1199 GL_BlendFunc(GL_ONE, GL_ONE);
1200 GL_DepthMask(false);
1202 qglPolygonOffset(0, 0);
1203 //qglDisable(GL_POLYGON_OFFSET_FILL);
1204 GL_Color(1, 1, 1, 1);
1205 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1207 qglDepthFunc(GL_LEQUAL);
1209 qglDepthFunc(GL_EQUAL);
1210 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1211 qglEnable(GL_CULL_FACE);
1213 qglEnable(GL_STENCIL_TEST);
1215 qglDisable(GL_STENCIL_TEST);
1217 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1218 // only draw light where this geometry was already rendered AND the
1219 // stencil is 128 (values other than this mean shadow)
1220 qglStencilFunc(GL_EQUAL, 128, ~0);
1221 r_shadow_rendermode = r_shadow_lightingrendermode;
1222 // do global setup needed for the chosen lighting mode
1223 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1225 R_Mesh_VertexPointer(varray_vertex3f);
1226 R_Mesh_TexCoordPointer(0, 2, varray_texcoord2f[0]);
1227 R_Mesh_TexCoordPointer(1, 3, varray_svector3f);
1228 R_Mesh_TexCoordPointer(2, 3, varray_tvector3f);
1229 R_Mesh_TexCoordPointer(3, 3, varray_normal3f);
1230 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1231 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1232 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1233 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1234 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1235 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1236 GL_BlendFunc(GL_ONE, GL_ONE);
1237 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1239 r_shadow_lightpermutation = 0;
1240 // only add a feature to the permutation if that permutation exists
1241 // (otherwise it might end up not using a shader at all, which looks
1242 // worse than using less features)
1243 if (fogenabled && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1244 r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1245 if (r_shadow_rtlight->specularscale && r_shadow_gloss.integer >= 1 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1246 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1247 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1248 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1249 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1250 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1251 if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
1252 r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
1253 if (r_shadow_glsl_usehalffloat.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
1254 r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
1255 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1256 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1257 // TODO: support fog (after renderer is converted to texture fog)
1258 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1260 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), fograngerecip);CHECKGLERROR
1262 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1263 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1264 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1266 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1267 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1269 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), r_shadow_entitylightcolorbase[0], r_shadow_entitylightcolorbase[1], r_shadow_entitylightcolorbase[2]);CHECKGLERROR
1270 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1271 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1273 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1275 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1277 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1278 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1283 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1285 R_Shadow_RenderMode_Reset();
1286 GL_BlendFunc(GL_ONE, GL_ONE);
1287 GL_DepthMask(false);
1288 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1289 qglPolygonOffset(0, 0);
1290 GL_Color(0.0, 0.0125, 0.1, 1);
1291 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1292 qglDepthFunc(GL_GEQUAL);
1293 qglCullFace(GL_FRONT); // this culls back
1294 qglDisable(GL_CULL_FACE);
1295 qglDisable(GL_STENCIL_TEST);
1296 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1299 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1301 R_Shadow_RenderMode_Reset();
1302 GL_BlendFunc(GL_ONE, GL_ONE);
1303 GL_DepthMask(false);
1304 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1305 qglPolygonOffset(0, 0);
1306 GL_Color(0.1, 0.0125, 0, 1);
1307 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1309 qglDepthFunc(GL_LEQUAL);
1311 qglDepthFunc(GL_EQUAL);
1312 qglCullFace(GL_FRONT); // this culls back
1313 qglEnable(GL_CULL_FACE);
1315 qglEnable(GL_STENCIL_TEST);
1317 qglDisable(GL_STENCIL_TEST);
1318 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1321 void R_Shadow_RenderMode_End(void)
1323 R_Shadow_RenderMode_Reset();
1324 R_Shadow_RenderMode_ActiveLight(NULL);
1325 GL_BlendFunc(GL_ONE, GL_ZERO);
1328 qglPolygonOffset(0, 0);
1329 //qglDisable(GL_POLYGON_OFFSET_FILL);
1330 GL_Color(1, 1, 1, 1);
1331 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1332 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1333 qglDepthFunc(GL_LEQUAL);
1334 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1335 qglEnable(GL_CULL_FACE);
1336 qglDisable(GL_STENCIL_TEST);
1337 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1338 if (gl_support_stenciltwoside)
1339 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1341 qglStencilFunc(GL_ALWAYS, 128, ~0);
1342 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1345 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1347 int i, ix1, iy1, ix2, iy2;
1348 float x1, y1, x2, y2;
1351 mplane_t planes[11];
1352 float vertex3f[256*3];
1354 // if view is inside the light box, just say yes it's visible
1355 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1357 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1361 // create a temporary brush describing the area the light can affect in worldspace
1362 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1363 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1364 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1365 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1366 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1367 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1368 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1369 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1370 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1371 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1372 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1374 // turn the brush into a mesh
1375 memset(&mesh, 0, sizeof(rmesh_t));
1376 mesh.maxvertices = 256;
1377 mesh.vertex3f = vertex3f;
1378 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1379 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1381 // if that mesh is empty, the light is not visible at all
1382 if (!mesh.numvertices)
1385 if (!r_shadow_scissor.integer)
1388 // if that mesh is not empty, check what area of the screen it covers
1389 x1 = y1 = x2 = y2 = 0;
1391 for (i = 0;i < mesh.numvertices;i++)
1393 VectorCopy(mesh.vertex3f + i * 3, v);
1394 GL_TransformToScreen(v, v2);
1395 //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]);
1398 if (x1 > v2[0]) x1 = v2[0];
1399 if (x2 < v2[0]) x2 = v2[0];
1400 if (y1 > v2[1]) y1 = v2[1];
1401 if (y2 < v2[1]) y2 = v2[1];
1410 // now convert the scissor rectangle to integer screen coordinates
1415 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1417 // clamp it to the screen
1418 if (ix1 < r_view_x) ix1 = r_view_x;
1419 if (iy1 < r_view_y) iy1 = r_view_y;
1420 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1421 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1423 // if it is inside out, it's not visible
1424 if (ix2 <= ix1 || iy2 <= iy1)
1427 // the light area is visible, set up the scissor rectangle
1428 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1429 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1430 //qglEnable(GL_SCISSOR_TEST);
1431 renderstats.lights_scissored++;
1435 extern float *rsurface_vertex3f;
1436 extern float *rsurface_svector3f;
1437 extern float *rsurface_tvector3f;
1438 extern float *rsurface_normal3f;
1439 extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
1441 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1443 int numverts = surface->num_vertices;
1444 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1445 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1446 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1447 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1448 if (r_textureunits.integer >= 3)
1450 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1452 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1453 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1454 if ((dot = DotProduct(n, v)) < 0)
1456 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1457 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) - reduce;
1458 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) - reduce;
1459 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) - reduce;
1462 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1463 VectorScale(color4f, f, color4f);
1467 VectorClear(color4f);
1471 else if (r_textureunits.integer >= 2)
1473 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1475 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1476 if ((dist = fabs(v[2])) < 1)
1478 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1479 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1480 if ((dot = DotProduct(n, v)) < 0)
1482 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1483 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
1484 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
1485 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
1489 color4f[0] = ambientcolor[0] * distintensity - reduce;
1490 color4f[1] = ambientcolor[1] * distintensity - reduce;
1491 color4f[2] = ambientcolor[2] * distintensity - reduce;
1495 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1496 VectorScale(color4f, f, color4f);
1500 VectorClear(color4f);
1506 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1508 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1509 if ((dist = DotProduct(v, v)) < 1)
1512 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1513 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1514 if ((dot = DotProduct(n, v)) < 0)
1516 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1517 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
1518 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
1519 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
1523 color4f[0] = ambientcolor[0] * distintensity - reduce;
1524 color4f[1] = ambientcolor[1] * distintensity - reduce;
1525 color4f[2] = ambientcolor[2] * distintensity - reduce;
1529 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1530 VectorScale(color4f, f, color4f);
1534 VectorClear(color4f);
1540 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1541 #define USETEXMATRIX
1543 #ifndef USETEXMATRIX
1544 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1545 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1546 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1550 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1551 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1552 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1559 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1563 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1564 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1572 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)
1576 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1578 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1579 // the cubemap normalizes this for us
1580 out3f[0] = DotProduct(svector3f, lightdir);
1581 out3f[1] = DotProduct(tvector3f, lightdir);
1582 out3f[2] = DotProduct(normal3f, lightdir);
1586 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)
1589 float lightdir[3], eyedir[3], halfdir[3];
1590 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1592 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1593 VectorNormalize(lightdir);
1594 VectorSubtract(relativeeyeorigin, vertex3f, eyedir);
1595 VectorNormalize(eyedir);
1596 VectorAdd(lightdir, eyedir, halfdir);
1597 // the cubemap normalizes this for us
1598 out3f[0] = DotProduct(svector3f, halfdir);
1599 out3f[1] = DotProduct(tvector3f, halfdir);
1600 out3f[2] = DotProduct(normal3f, halfdir);
1604 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)
1606 // used to display how many times a surface is lit for level design purposes
1607 int surfacelistindex;
1609 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1610 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1611 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1612 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1613 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1614 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1615 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1616 if (!doambientbase && !dodiffusebase && !doambientpants && !dodiffusepants && !doambientshirt && !dodiffuseshirt && !dospecular)
1618 GL_Color(0.1, 0.025, 0, 1);
1619 memset(&m, 0, sizeof(m));
1621 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1623 const msurface_t *surface = surfacelist[surfacelistindex];
1624 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
1625 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1626 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
1627 GL_LockArrays(0, 0);
1631 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)
1633 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1634 int surfacelistindex;
1635 qboolean dobase = (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1636 qboolean dopants = (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1637 qboolean doshirt = (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1638 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1639 // TODO: add direct pants/shirt rendering
1641 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);
1643 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);
1644 if (!dobase && !dospecular)
1646 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
1647 R_Mesh_TexBind(0, R_GetTexture(normalmaptexture));
1648 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1649 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1650 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1652 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1654 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1655 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1657 const msurface_t *surface = surfacelist[surfacelistindex];
1658 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1659 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
1660 if (!rsurface_svector3f)
1662 rsurface_svector3f = varray_svector3f;
1663 rsurface_tvector3f = varray_tvector3f;
1664 rsurface_normal3f = varray_normal3f;
1665 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);
1667 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1668 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1669 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1670 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1671 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1672 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1673 GL_LockArrays(0, 0);
1677 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)
1679 // ARB path (any Geforce, any Radeon)
1680 int surfacelistindex;
1682 float color2[3], colorscale;
1684 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1685 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1686 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1687 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1688 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1689 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1690 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1691 // TODO: add direct pants/shirt rendering
1692 if (doambientpants || dodiffusepants)
1693 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);
1694 if (doambientshirt || dodiffuseshirt)
1695 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);
1696 if (!doambientbase && !dodiffusebase && !dospecular)
1698 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1700 const msurface_t *surface = surfacelist[surfacelistindex];
1701 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1702 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
1703 if (!rsurface_svector3f)
1705 rsurface_svector3f = varray_svector3f;
1706 rsurface_tvector3f = varray_tvector3f;
1707 rsurface_normal3f = varray_normal3f;
1708 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);
1713 colorscale = r_shadow_rtlight->ambientscale;
1714 // colorscale accounts for how much we multiply the brightness
1717 // mult is how many times the final pass of the lighting will be
1718 // performed to get more brightness than otherwise possible.
1720 // Limit mult to 64 for sanity sake.
1721 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1723 // 3 3D combine path (Geforce3, Radeon 8500)
1724 memset(&m, 0, sizeof(m));
1725 m.pointer_vertex = rsurface_vertex3f;
1726 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1728 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1729 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1731 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1732 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1734 m.tex[1] = R_GetTexture(basetexture);
1735 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1736 m.texmatrix[1] = texture->currenttexmatrix;
1737 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1739 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1740 m.texmatrix[2] = r_shadow_entitytolight;
1742 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1743 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1745 GL_BlendFunc(GL_ONE, GL_ONE);
1747 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1749 // 2 3D combine path (Geforce3, original Radeon)
1750 memset(&m, 0, sizeof(m));
1751 m.pointer_vertex = rsurface_vertex3f;
1752 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1754 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1755 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1757 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1758 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1760 m.tex[1] = R_GetTexture(basetexture);
1761 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1762 m.texmatrix[1] = texture->currenttexmatrix;
1763 GL_BlendFunc(GL_ONE, GL_ONE);
1765 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1767 // 4 2D combine path (Geforce3, Radeon 8500)
1768 memset(&m, 0, sizeof(m));
1769 m.pointer_vertex = rsurface_vertex3f;
1770 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1772 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1773 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1775 m.pointer_texcoord[0] = varray_texcoord2f[0];
1776 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1778 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1780 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1781 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1783 m.pointer_texcoord[1] = varray_texcoord2f[1];
1784 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1786 m.tex[2] = R_GetTexture(basetexture);
1787 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1788 m.texmatrix[2] = texture->currenttexmatrix;
1789 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1791 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1793 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1794 m.texmatrix[3] = r_shadow_entitytolight;
1796 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1797 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1800 GL_BlendFunc(GL_ONE, GL_ONE);
1802 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1804 // 3 2D combine path (Geforce3, original Radeon)
1805 memset(&m, 0, sizeof(m));
1806 m.pointer_vertex = rsurface_vertex3f;
1807 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1809 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1810 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1812 m.pointer_texcoord[0] = varray_texcoord2f[0];
1813 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1815 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1817 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1818 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1820 m.pointer_texcoord[1] = varray_texcoord2f[1];
1821 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1823 m.tex[2] = R_GetTexture(basetexture);
1824 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1825 m.texmatrix[2] = texture->currenttexmatrix;
1826 GL_BlendFunc(GL_ONE, GL_ONE);
1830 // 2/2/2 2D combine path (any dot3 card)
1831 memset(&m, 0, sizeof(m));
1832 m.pointer_vertex = rsurface_vertex3f;
1833 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1835 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1836 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1838 m.pointer_texcoord[0] = varray_texcoord2f[0];
1839 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1841 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1843 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1844 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1846 m.pointer_texcoord[1] = varray_texcoord2f[1];
1847 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1850 GL_ColorMask(0,0,0,1);
1851 GL_BlendFunc(GL_ONE, GL_ZERO);
1852 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1853 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1854 GL_LockArrays(0, 0);
1856 memset(&m, 0, sizeof(m));
1857 m.pointer_vertex = rsurface_vertex3f;
1858 m.tex[0] = R_GetTexture(basetexture);
1859 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1860 m.texmatrix[0] = texture->currenttexmatrix;
1861 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1863 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1865 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1866 m.texmatrix[1] = r_shadow_entitytolight;
1868 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1869 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1872 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1874 // this final code is shared
1876 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1877 VectorScale(lightcolorbase, colorscale, color2);
1878 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1879 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1881 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1882 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1884 GL_LockArrays(0, 0);
1889 colorscale = r_shadow_rtlight->diffusescale;
1890 // colorscale accounts for how much we multiply the brightness
1893 // mult is how many times the final pass of the lighting will be
1894 // performed to get more brightness than otherwise possible.
1896 // Limit mult to 64 for sanity sake.
1897 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1899 // 3/2 3D combine path (Geforce3, Radeon 8500)
1900 memset(&m, 0, sizeof(m));
1901 m.pointer_vertex = rsurface_vertex3f;
1902 m.tex[0] = R_GetTexture(normalmaptexture);
1903 m.texcombinergb[0] = GL_REPLACE;
1904 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1905 m.texmatrix[0] = texture->currenttexmatrix;
1906 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1907 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1908 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1909 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);
1910 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1912 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1913 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1915 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1916 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1919 GL_ColorMask(0,0,0,1);
1920 GL_BlendFunc(GL_ONE, GL_ZERO);
1921 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1922 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1923 GL_LockArrays(0, 0);
1925 memset(&m, 0, sizeof(m));
1926 m.pointer_vertex = rsurface_vertex3f;
1927 m.tex[0] = R_GetTexture(basetexture);
1928 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1929 m.texmatrix[0] = texture->currenttexmatrix;
1930 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1932 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1934 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1935 m.texmatrix[1] = r_shadow_entitytolight;
1937 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1938 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1941 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1943 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1945 // 1/2/2 3D combine path (original Radeon)
1946 memset(&m, 0, sizeof(m));
1947 m.pointer_vertex = rsurface_vertex3f;
1948 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1950 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1951 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1953 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1954 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1957 GL_ColorMask(0,0,0,1);
1958 GL_BlendFunc(GL_ONE, GL_ZERO);
1959 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1960 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1961 GL_LockArrays(0, 0);
1963 memset(&m, 0, sizeof(m));
1964 m.pointer_vertex = rsurface_vertex3f;
1965 m.tex[0] = R_GetTexture(normalmaptexture);
1966 m.texcombinergb[0] = GL_REPLACE;
1967 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1968 m.texmatrix[0] = texture->currenttexmatrix;
1969 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1970 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1971 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1972 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);
1974 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1975 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1976 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1977 GL_LockArrays(0, 0);
1979 memset(&m, 0, sizeof(m));
1980 m.pointer_vertex = rsurface_vertex3f;
1981 m.tex[0] = R_GetTexture(basetexture);
1982 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1983 m.texmatrix[0] = texture->currenttexmatrix;
1984 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1986 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1988 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1989 m.texmatrix[1] = r_shadow_entitytolight;
1991 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1992 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1995 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1997 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1999 // 2/2 3D combine path (original Radeon)
2000 memset(&m, 0, sizeof(m));
2001 m.pointer_vertex = rsurface_vertex3f;
2002 m.tex[0] = R_GetTexture(normalmaptexture);
2003 m.texcombinergb[0] = GL_REPLACE;
2004 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2005 m.texmatrix[0] = texture->currenttexmatrix;
2006 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2007 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2008 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2009 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);
2011 GL_ColorMask(0,0,0,1);
2012 GL_BlendFunc(GL_ONE, GL_ZERO);
2013 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2014 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2015 GL_LockArrays(0, 0);
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 memset(&m, 0, sizeof(m));
2069 m.pointer_vertex = rsurface_vertex3f;
2070 m.tex[0] = R_GetTexture(basetexture);
2071 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2072 m.texmatrix[0] = texture->currenttexmatrix;
2073 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2075 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2077 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2078 m.texmatrix[1] = r_shadow_entitytolight;
2080 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2081 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2084 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2088 // 2/2/2 2D combine path (any dot3 card)
2089 memset(&m, 0, sizeof(m));
2090 m.pointer_vertex = rsurface_vertex3f;
2091 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2093 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2094 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2096 m.pointer_texcoord[0] = varray_texcoord2f[0];
2097 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2099 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2101 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2102 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2104 m.pointer_texcoord[1] = varray_texcoord2f[1];
2105 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2108 GL_ColorMask(0,0,0,1);
2109 GL_BlendFunc(GL_ONE, GL_ZERO);
2110 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2111 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2112 GL_LockArrays(0, 0);
2114 memset(&m, 0, sizeof(m));
2115 m.pointer_vertex = rsurface_vertex3f;
2116 m.tex[0] = R_GetTexture(normalmaptexture);
2117 m.texcombinergb[0] = GL_REPLACE;
2118 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2119 m.texmatrix[0] = texture->currenttexmatrix;
2120 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2121 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2122 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2123 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);
2125 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2126 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2127 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2128 GL_LockArrays(0, 0);
2130 memset(&m, 0, sizeof(m));
2131 m.pointer_vertex = rsurface_vertex3f;
2132 m.tex[0] = R_GetTexture(basetexture);
2133 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2134 m.texmatrix[0] = texture->currenttexmatrix;
2135 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2137 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2139 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2140 m.texmatrix[1] = r_shadow_entitytolight;
2142 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2143 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2146 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2148 // this final code is shared
2150 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2151 VectorScale(lightcolorbase, colorscale, color2);
2152 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2153 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2155 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2156 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2158 GL_LockArrays(0, 0);
2162 // FIXME: detect blendsquare!
2163 //if (gl_support_blendsquare)
2165 colorscale = specularscale;
2167 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2169 // 2/0/0/1/2 3D combine blendsquare path
2170 memset(&m, 0, sizeof(m));
2171 m.pointer_vertex = rsurface_vertex3f;
2172 m.tex[0] = R_GetTexture(normalmaptexture);
2173 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2174 m.texmatrix[0] = texture->currenttexmatrix;
2175 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2176 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2177 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2178 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);
2180 GL_ColorMask(0,0,0,1);
2181 // this squares the result
2182 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2183 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2184 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2185 GL_LockArrays(0, 0);
2187 memset(&m, 0, sizeof(m));
2188 m.pointer_vertex = rsurface_vertex3f;
2190 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2191 // square alpha in framebuffer a few times to make it shiny
2192 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2193 // these comments are a test run through this math for intensity 0.5
2194 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2195 // 0.25 * 0.25 = 0.0625 (this is another pass)
2196 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2197 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2198 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2199 GL_LockArrays(0, 0);
2201 memset(&m, 0, sizeof(m));
2202 m.pointer_vertex = rsurface_vertex3f;
2203 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2205 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2206 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2208 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2209 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2212 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2213 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2214 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2215 GL_LockArrays(0, 0);
2217 memset(&m, 0, sizeof(m));
2218 m.pointer_vertex = rsurface_vertex3f;
2219 m.tex[0] = R_GetTexture(glosstexture);
2220 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2221 m.texmatrix[0] = texture->currenttexmatrix;
2222 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2224 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2226 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2227 m.texmatrix[1] = r_shadow_entitytolight;
2229 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2230 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2233 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2235 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2237 // 2/0/0/2 3D combine blendsquare path
2238 memset(&m, 0, sizeof(m));
2239 m.pointer_vertex = rsurface_vertex3f;
2240 m.tex[0] = R_GetTexture(normalmaptexture);
2241 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2242 m.texmatrix[0] = texture->currenttexmatrix;
2243 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2244 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2245 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2246 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);
2248 GL_ColorMask(0,0,0,1);
2249 // this squares the result
2250 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2251 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2252 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2253 GL_LockArrays(0, 0);
2255 memset(&m, 0, sizeof(m));
2256 m.pointer_vertex = rsurface_vertex3f;
2258 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2259 // square alpha in framebuffer a few times to make it shiny
2260 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2261 // these comments are a test run through this math for intensity 0.5
2262 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2263 // 0.25 * 0.25 = 0.0625 (this is another pass)
2264 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2265 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2266 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2267 GL_LockArrays(0, 0);
2269 memset(&m, 0, sizeof(m));
2270 m.pointer_vertex = rsurface_vertex3f;
2271 m.tex[0] = R_GetTexture(glosstexture);
2272 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2273 m.texmatrix[0] = texture->currenttexmatrix;
2274 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2276 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2277 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2279 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2280 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2282 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2286 // 2/0/0/2/2 2D combine blendsquare path
2287 memset(&m, 0, sizeof(m));
2288 m.pointer_vertex = rsurface_vertex3f;
2289 m.tex[0] = R_GetTexture(normalmaptexture);
2290 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2291 m.texmatrix[0] = texture->currenttexmatrix;
2292 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2293 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2294 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2295 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);
2297 GL_ColorMask(0,0,0,1);
2298 // this squares the result
2299 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2300 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2301 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2302 GL_LockArrays(0, 0);
2304 memset(&m, 0, sizeof(m));
2305 m.pointer_vertex = rsurface_vertex3f;
2307 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2308 // square alpha in framebuffer a few times to make it shiny
2309 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2310 // these comments are a test run through this math for intensity 0.5
2311 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2312 // 0.25 * 0.25 = 0.0625 (this is another pass)
2313 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2314 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2315 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2316 GL_LockArrays(0, 0);
2318 memset(&m, 0, sizeof(m));
2319 m.pointer_vertex = rsurface_vertex3f;
2320 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2322 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2323 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2325 m.pointer_texcoord[0] = varray_texcoord2f[0];
2326 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2328 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2330 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2331 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2333 m.pointer_texcoord[1] = varray_texcoord2f[1];
2334 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2337 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2338 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2339 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2340 GL_LockArrays(0, 0);
2342 memset(&m, 0, sizeof(m));
2343 m.pointer_vertex = rsurface_vertex3f;
2344 m.tex[0] = R_GetTexture(glosstexture);
2345 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2346 m.texmatrix[0] = texture->currenttexmatrix;
2347 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2349 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2351 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2352 m.texmatrix[1] = r_shadow_entitytolight;
2354 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2355 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2358 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2361 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2362 VectorScale(lightcolorbase, colorscale, color2);
2363 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2364 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2366 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2367 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2369 GL_LockArrays(0, 0);
2375 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)
2377 int surfacelistindex;
2379 float ambientcolor2[3], diffusecolor2[3];
2381 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
2382 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
2383 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
2384 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
2385 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
2386 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
2387 //qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
2388 // TODO: add direct pants/shirt rendering
2389 if (doambientpants || dodiffusepants)
2390 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);
2391 if (doambientshirt || dodiffuseshirt)
2392 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);
2393 if (!doambientbase && !dodiffusebase)
2395 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, ambientcolor2);
2396 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, diffusecolor2);
2397 GL_BlendFunc(GL_ONE, GL_ONE);
2398 memset(&m, 0, sizeof(m));
2399 m.tex[0] = R_GetTexture(basetexture);
2400 if (r_textureunits.integer >= 2)
2403 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2405 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2407 m.pointer_texcoord[1] = varray_texcoord2f[1];
2408 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2410 if (r_textureunits.integer >= 3)
2412 // Geforce3/Radeon class but not using dot3
2413 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2415 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2417 m.pointer_texcoord[2] = varray_texcoord2f[2];
2418 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2422 m.pointer_color = varray_color4f;
2424 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2426 const msurface_t *surface = surfacelist[surfacelistindex];
2427 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2428 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
2429 if (!rsurface_svector3f)
2431 rsurface_svector3f = varray_svector3f;
2432 rsurface_tvector3f = varray_tvector3f;
2433 rsurface_normal3f = varray_normal3f;
2434 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);
2436 // OpenGL 1.1 path (anything)
2437 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2438 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
2439 if (r_textureunits.integer >= 2)
2443 R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
2445 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2447 if (r_textureunits.integer >= 3)
2449 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2451 R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
2453 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2457 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2, 0);
2458 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
2463 // due to low fillrate on the cards this vertex lighting path is
2464 // designed for, we manually cull all triangles that do not
2465 // contain a lit vertex
2468 int newnumtriangles;
2470 int newelements[3072];
2472 newnumtriangles = 0;
2474 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
2476 if (newnumtriangles >= 1024)
2478 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2479 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
2480 GL_LockArrays(0, 0);
2481 newnumtriangles = 0;
2484 if (VectorLength2(varray_color4f + e[0] * 4) + VectorLength2(varray_color4f + e[1] * 4) + VectorLength2(varray_color4f + e[2] * 4) >= 0.01)
2494 if (newnumtriangles >= 1)
2496 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2497 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
2498 GL_LockArrays(0, 0);
2504 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
2505 if (VectorLength2(c))
2509 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2510 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2511 GL_LockArrays(0, 0);
2513 // now reduce the intensity for the next overbright pass
2514 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
2516 c[0] = max(0, c[0] - 1);
2517 c[1] = max(0, c[1] - 1);
2518 c[2] = max(0, c[2] - 1);
2524 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
2526 // FIXME: support MATERIALFLAG_NODEPTHTEST
2527 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2528 rtexture_t *basetexture;
2529 rtexture_t *glosstexture;
2530 float specularscale;
2531 if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
2532 qglDisable(GL_CULL_FACE);
2534 qglEnable(GL_CULL_FACE);
2535 glosstexture = r_texture_black;
2537 if (r_shadow_gloss.integer > 0)
2539 if (texture->skin.gloss)
2541 if (r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
2543 glosstexture = texture->skin.gloss;
2544 specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
2549 if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
2551 glosstexture = r_texture_white;
2552 specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
2556 // calculate colors to render this texture with
2557 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
2558 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
2559 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
2560 lightcolorpants[0] = r_shadow_rtlight->currentcolor[0] * ent->colormap_pantscolor[0] * texture->currentalpha;
2561 lightcolorpants[1] = r_shadow_rtlight->currentcolor[1] * ent->colormap_pantscolor[1] * texture->currentalpha;
2562 lightcolorpants[2] = r_shadow_rtlight->currentcolor[2] * ent->colormap_pantscolor[2] * texture->currentalpha;
2563 lightcolorshirt[0] = r_shadow_rtlight->currentcolor[0] * ent->colormap_shirtcolor[0] * texture->currentalpha;
2564 lightcolorshirt[1] = r_shadow_rtlight->currentcolor[1] * ent->colormap_shirtcolor[1] * texture->currentalpha;
2565 lightcolorshirt[2] = r_shadow_rtlight->currentcolor[2] * ent->colormap_shirtcolor[2] * texture->currentalpha;
2566 if (ent->colormap >= 0)
2568 basetexture = texture->skin.base;
2569 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2574 basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
2575 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2578 switch (r_shadow_rendermode)
2580 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2581 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
2583 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2584 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
2586 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2587 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
2589 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2590 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
2593 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2598 void R_RTLight_Update(dlight_t *light, int isstatic)
2602 rtlight_t *rtlight = &light->rtlight;
2603 R_RTLight_Uncompile(rtlight);
2604 memset(rtlight, 0, sizeof(*rtlight));
2606 VectorCopy(light->origin, rtlight->shadoworigin);
2607 VectorCopy(light->color, rtlight->color);
2608 rtlight->radius = light->radius;
2609 //rtlight->cullradius = rtlight->radius;
2610 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2611 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2612 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2613 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2614 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2615 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2616 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2617 rtlight->cubemapname[0] = 0;
2618 if (light->cubemapname[0])
2619 strcpy(rtlight->cubemapname, light->cubemapname);
2620 else if (light->cubemapnum > 0)
2621 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2622 rtlight->shadow = light->shadow;
2623 rtlight->corona = light->corona;
2624 rtlight->style = light->style;
2625 rtlight->isstatic = isstatic;
2626 rtlight->coronasizescale = light->coronasizescale;
2627 rtlight->ambientscale = light->ambientscale;
2628 rtlight->diffusescale = light->diffusescale;
2629 rtlight->specularscale = light->specularscale;
2630 rtlight->flags = light->flags;
2631 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2632 // ConcatScale won't work here because this needs to scale rotate and
2633 // translate, not just rotate
2634 scale = 1.0f / rtlight->radius;
2635 for (k = 0;k < 3;k++)
2636 for (j = 0;j < 4;j++)
2637 rtlight->matrix_worldtolight.m[k][j] *= scale;
2639 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2640 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2641 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2642 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2645 // compiles rtlight geometry
2646 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2647 void R_RTLight_Compile(rtlight_t *rtlight)
2649 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2650 entity_render_t *ent = r_refdef.worldentity;
2651 model_t *model = r_refdef.worldmodel;
2652 unsigned char *data;
2654 // compile the light
2655 rtlight->compiled = true;
2656 rtlight->static_numleafs = 0;
2657 rtlight->static_numleafpvsbytes = 0;
2658 rtlight->static_leaflist = NULL;
2659 rtlight->static_leafpvs = NULL;
2660 rtlight->static_numsurfaces = 0;
2661 rtlight->static_surfacelist = NULL;
2662 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2663 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2664 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2665 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2666 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2667 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2669 if (model && model->GetLightInfo)
2671 // this variable must be set for the CompileShadowVolume code
2672 r_shadow_compilingrtlight = rtlight;
2673 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2674 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);
2675 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2676 data = (unsigned char *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2677 rtlight->static_numleafs = numleafs;
2678 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2679 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2680 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2681 rtlight->static_numsurfaces = numsurfaces;
2682 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2684 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2685 if (numleafpvsbytes)
2686 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2688 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2689 if (model->CompileShadowVolume && rtlight->shadow)
2690 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2691 // now we're done compiling the rtlight
2692 r_shadow_compilingrtlight = NULL;
2696 // use smallest available cullradius - box radius or light radius
2697 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2698 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2702 if (rtlight->static_meshchain_shadow)
2705 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2708 shadowtris += mesh->numtriangles;
2712 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);
2715 void R_RTLight_Uncompile(rtlight_t *rtlight)
2717 if (rtlight->compiled)
2719 if (rtlight->static_meshchain_shadow)
2720 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2721 rtlight->static_meshchain_shadow = NULL;
2722 // these allocations are grouped
2723 if (rtlight->static_leaflist)
2724 Mem_Free(rtlight->static_leaflist);
2725 rtlight->static_numleafs = 0;
2726 rtlight->static_numleafpvsbytes = 0;
2727 rtlight->static_leaflist = NULL;
2728 rtlight->static_leafpvs = NULL;
2729 rtlight->static_numsurfaces = 0;
2730 rtlight->static_surfacelist = NULL;
2731 rtlight->compiled = false;
2735 void R_Shadow_UncompileWorldLights(void)
2738 for (light = r_shadow_worldlightchain;light;light = light->next)
2739 R_RTLight_Uncompile(&light->rtlight);
2742 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2744 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2745 vec_t relativeshadowradius;
2746 if (ent == r_refdef.worldentity)
2748 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2751 R_Mesh_Matrix(&ent->matrix);
2752 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2754 renderstats.lights_shadowtriangles += mesh->numtriangles;
2755 R_Mesh_VertexPointer(mesh->vertex3f);
2756 GL_LockArrays(0, mesh->numverts);
2757 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2759 // decrement stencil if backface is behind depthbuffer
2760 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2761 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2762 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2763 // increment stencil if frontface is behind depthbuffer
2764 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2765 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2767 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2768 GL_LockArrays(0, 0);
2771 else if (numsurfaces)
2773 R_Mesh_Matrix(&ent->matrix);
2774 ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2779 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2780 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2781 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2782 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2783 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2784 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2785 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2786 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2787 R_Mesh_Matrix(&ent->matrix);
2788 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2792 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2794 // set up properties for rendering light onto this entity
2795 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2796 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2797 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2798 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2799 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2800 R_Mesh_Matrix(&ent->matrix);
2801 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2803 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2804 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2805 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2807 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2812 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2814 R_Shadow_SetupEntityLight(ent);
2815 if (ent == r_refdef.worldentity)
2816 ent->model->DrawLight(ent, numsurfaces, surfacelist);
2818 ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
2821 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2825 int numleafs, numsurfaces;
2826 int *leaflist, *surfacelist;
2827 unsigned char *leafpvs;
2828 int numlightentities;
2829 int numshadowentities;
2830 entity_render_t *lightentities[MAX_EDICTS];
2831 entity_render_t *shadowentities[MAX_EDICTS];
2833 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2834 // skip lights that are basically invisible (color 0 0 0)
2835 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2838 // loading is done before visibility checks because loading should happen
2839 // all at once at the start of a level, not when it stalls gameplay.
2840 // (especially important to benchmarks)
2842 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2843 R_RTLight_Compile(rtlight);
2845 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2847 // look up the light style value at this time
2848 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2849 VectorScale(rtlight->color, f, rtlight->currentcolor);
2851 if (rtlight->selected)
2853 f = 2 + sin(realtime * M_PI * 4.0);
2854 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2858 // if lightstyle is currently off, don't draw the light
2859 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2862 // if the light box is offscreen, skip it
2863 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2866 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2868 // compiled light, world available and can receive realtime lighting
2869 // retrieve leaf information
2870 numleafs = rtlight->static_numleafs;
2871 leaflist = rtlight->static_leaflist;
2872 leafpvs = rtlight->static_leafpvs;
2873 numsurfaces = rtlight->static_numsurfaces;
2874 surfacelist = rtlight->static_surfacelist;
2876 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2878 // dynamic light, world available and can receive realtime lighting
2879 // calculate lit surfaces and leafs
2880 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2881 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);
2882 leaflist = r_shadow_buffer_leaflist;
2883 leafpvs = r_shadow_buffer_leafpvs;
2884 surfacelist = r_shadow_buffer_surfacelist;
2885 // if the reduced leaf bounds are offscreen, skip it
2886 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2898 // check if light is illuminating any visible leafs
2901 for (i = 0;i < numleafs;i++)
2902 if (r_worldleafvisible[leaflist[i]])
2907 // set up a scissor rectangle for this light
2908 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2911 // make a list of lit entities and shadow casting entities
2912 numlightentities = 0;
2913 numshadowentities = 0;
2914 // don't count the world unless some surfaces are actually lit
2917 lightentities[numlightentities++] = r_refdef.worldentity;
2918 shadowentities[numshadowentities++] = r_refdef.worldentity;
2920 // add dynamic entities that are lit by the light
2921 if (r_drawentities.integer)
2923 for (i = 0;i < r_refdef.numentities;i++)
2925 entity_render_t *ent = r_refdef.entities[i];
2926 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2928 && !(ent->flags & RENDER_TRANSPARENT)
2929 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2931 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2932 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2933 shadowentities[numshadowentities++] = ent;
2934 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2935 lightentities[numlightentities++] = ent;
2940 // return if there's nothing at all to light
2941 if (!numlightentities)
2944 // make this the active rtlight for rendering purposes
2945 R_Shadow_RenderMode_ActiveLight(rtlight);
2946 // count this light in the r_speeds
2947 renderstats.lights++;
2949 // draw stencil shadow volumes to mask off pixels that are in shadow
2950 // so that they won't receive lighting
2952 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2955 R_Shadow_RenderMode_StencilShadowVolumes();
2956 for (i = 0;i < numshadowentities;i++)
2957 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2960 // draw lighting in the unmasked areas
2961 if (numlightentities && !visible)
2963 R_Shadow_RenderMode_Lighting(usestencil, false);
2964 for (i = 0;i < numlightentities;i++)
2965 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2968 // optionally draw visible shape of the shadow volumes
2969 // for performance analysis by level designers
2970 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2972 R_Shadow_RenderMode_VisibleShadowVolumes();
2973 for (i = 0;i < numshadowentities;i++)
2974 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2977 // optionally draw the illuminated areas
2978 // for performance analysis by level designers
2979 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2981 R_Shadow_RenderMode_VisibleLighting(usestencil, false);
2982 for (i = 0;i < numlightentities;i++)
2983 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2987 void R_ShadowVolumeLighting(qboolean visible)
2992 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2993 R_Shadow_EditLights_Reload_f();
2995 R_Shadow_RenderMode_Begin();
2997 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2998 if (r_shadow_debuglight.integer >= 0)
3000 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3001 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3002 R_DrawRTLight(&light->rtlight, visible);
3005 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3006 if (light->flags & flag)
3007 R_DrawRTLight(&light->rtlight, visible);
3009 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3010 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
3012 R_Shadow_RenderMode_End();
3015 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3016 typedef struct suffixinfo_s
3019 qboolean flipx, flipy, flipdiagonal;
3022 static suffixinfo_t suffix[3][6] =
3025 {"px", false, false, false},
3026 {"nx", false, false, false},
3027 {"py", false, false, false},
3028 {"ny", false, false, false},
3029 {"pz", false, false, false},
3030 {"nz", false, false, false}
3033 {"posx", false, false, false},
3034 {"negx", false, false, false},
3035 {"posy", false, false, false},
3036 {"negy", false, false, false},
3037 {"posz", false, false, false},
3038 {"negz", false, false, false}
3041 {"rt", true, false, true},
3042 {"lf", false, true, true},
3043 {"ft", true, true, false},
3044 {"bk", false, false, false},
3045 {"up", true, false, true},
3046 {"dn", true, false, true}
3050 static int componentorder[4] = {0, 1, 2, 3};
3052 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3054 int i, j, cubemapsize;
3055 unsigned char *cubemappixels, *image_rgba;
3056 rtexture_t *cubemaptexture;
3058 // must start 0 so the first loadimagepixels has no requested width/height
3060 cubemappixels = NULL;
3061 cubemaptexture = NULL;
3062 // keep trying different suffix groups (posx, px, rt) until one loads
3063 for (j = 0;j < 3 && !cubemappixels;j++)
3065 // load the 6 images in the suffix group
3066 for (i = 0;i < 6;i++)
3068 // generate an image name based on the base and and suffix
3069 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3071 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3073 // an image loaded, make sure width and height are equal
3074 if (image_width == image_height)
3076 // if this is the first image to load successfully, allocate the cubemap memory
3077 if (!cubemappixels && image_width >= 1)
3079 cubemapsize = image_width;
3080 // note this clears to black, so unavailable sides are black
3081 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3083 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3085 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);
3088 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3090 Mem_Free(image_rgba);
3094 // if a cubemap loaded, upload it
3097 if (!r_shadow_filters_texturepool)
3098 r_shadow_filters_texturepool = R_AllocTexturePool();
3099 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3100 Mem_Free(cubemappixels);
3104 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3105 for (j = 0;j < 3;j++)
3106 for (i = 0;i < 6;i++)
3107 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3108 Con_Print(" and was unable to find any of them.\n");
3110 return cubemaptexture;
3113 rtexture_t *R_Shadow_Cubemap(const char *basename)
3116 for (i = 0;i < numcubemaps;i++)
3117 if (!strcasecmp(cubemaps[i].basename, basename))
3118 return cubemaps[i].texture;
3119 if (i >= MAX_CUBEMAPS)
3120 return r_texture_whitecube;
3122 strcpy(cubemaps[i].basename, basename);
3123 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3124 if (!cubemaps[i].texture)
3125 cubemaps[i].texture = r_texture_whitecube;
3126 return cubemaps[i].texture;
3129 void R_Shadow_FreeCubemaps(void)
3132 R_FreeTexturePool(&r_shadow_filters_texturepool);
3135 dlight_t *R_Shadow_NewWorldLight(void)
3138 light = (dlight_t *)Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3139 light->next = r_shadow_worldlightchain;
3140 r_shadow_worldlightchain = light;
3144 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)
3146 VectorCopy(origin, light->origin);
3147 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3148 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3149 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3150 light->color[0] = max(color[0], 0);
3151 light->color[1] = max(color[1], 0);
3152 light->color[2] = max(color[2], 0);
3153 light->radius = max(radius, 0);
3154 light->style = style;
3155 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3157 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3160 light->shadow = shadowenable;
3161 light->corona = corona;
3164 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3165 light->coronasizescale = coronasizescale;
3166 light->ambientscale = ambientscale;
3167 light->diffusescale = diffusescale;
3168 light->specularscale = specularscale;
3169 light->flags = flags;
3170 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3172 R_RTLight_Update(light, true);
3175 void R_Shadow_FreeWorldLight(dlight_t *light)
3177 dlight_t **lightpointer;
3178 R_RTLight_Uncompile(&light->rtlight);
3179 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3180 if (*lightpointer != light)
3181 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3182 *lightpointer = light->next;
3186 void R_Shadow_ClearWorldLights(void)
3188 while (r_shadow_worldlightchain)
3189 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3190 r_shadow_selectedlight = NULL;
3191 R_Shadow_FreeCubemaps();
3194 void R_Shadow_SelectLight(dlight_t *light)
3196 if (r_shadow_selectedlight)
3197 r_shadow_selectedlight->selected = false;
3198 r_shadow_selectedlight = light;
3199 if (r_shadow_selectedlight)
3200 r_shadow_selectedlight->selected = true;
3203 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
3205 float scale = r_editlights_cursorgrid.value * 0.5f;
3206 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
3209 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
3212 const dlight_t *light = (dlight_t *)ent;
3214 if (light->selected)
3215 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3218 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[surfacenumber], NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
3221 void R_Shadow_DrawLightSprites(void)
3227 for (i = 0;i < 5;i++)
3229 lighttextures[i] = NULL;
3230 if ((pic = Draw_CachePic(va("gfx/crosshair%i", i + 1), true)))
3231 lighttextures[i] = pic->tex;
3234 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3235 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, i % 5, &light->rtlight);
3236 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3239 void R_Shadow_SelectLightInView(void)
3241 float bestrating, rating, temp[3];
3242 dlight_t *best, *light;
3245 for (light = r_shadow_worldlightchain;light;light = light->next)
3247 VectorSubtract(light->origin, r_vieworigin, temp);
3248 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3251 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3252 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3254 bestrating = rating;
3259 R_Shadow_SelectLight(best);
3262 void R_Shadow_LoadWorldLights(void)
3264 int n, a, style, shadow, flags;
3265 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3266 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3267 if (r_refdef.worldmodel == NULL)
3269 Con_Print("No map loaded.\n");
3272 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3273 strlcat (name, ".rtlights", sizeof (name));
3274 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3284 for (;COM_Parse(t, true) && strcmp(
3285 if (COM_Parse(t, true))
3287 if (com_token[0] == '!')
3290 origin[0] = atof(com_token+1);
3293 origin[0] = atof(com_token);
3298 while (*s && *s != '\n' && *s != '\r')
3304 // check for modifier flags
3311 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);
3314 flags = LIGHTFLAG_REALTIMEMODE;
3322 coronasizescale = 0.25f;
3324 VectorClear(angles);
3327 if (a < 9 || !strcmp(cubemapname, "\"\""))
3329 // remove quotes on cubemapname
3330 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3332 cubemapname[strlen(cubemapname)-1] = 0;
3333 strcpy(cubemapname, cubemapname + 1);
3337 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);
3340 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3348 Con_Printf("invalid rtlights file \"%s\"\n", name);
3349 Mem_Free(lightsstring);
3353 void R_Shadow_SaveWorldLights(void)
3356 size_t bufchars, bufmaxchars;
3358 char name[MAX_QPATH];
3359 char line[MAX_INPUTLINE];
3360 if (!r_shadow_worldlightchain)
3362 if (r_refdef.worldmodel == NULL)
3364 Con_Print("No map loaded.\n");
3367 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3368 strlcat (name, ".rtlights", sizeof (name));
3369 bufchars = bufmaxchars = 0;
3371 for (light = r_shadow_worldlightchain;light;light = light->next)
3373 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3374 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);
3375 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3376 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]);
3378 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);
3379 if (bufchars + strlen(line) > bufmaxchars)
3381 bufmaxchars = bufchars + strlen(line) + 2048;
3383 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3387 memcpy(buf, oldbuf, bufchars);
3393 memcpy(buf + bufchars, line, strlen(line));
3394 bufchars += strlen(line);
3398 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3403 void R_Shadow_LoadLightsFile(void)
3406 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3407 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3408 if (r_refdef.worldmodel == NULL)
3410 Con_Print("No map loaded.\n");
3413 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3414 strlcat (name, ".lights", sizeof (name));
3415 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3423 while (*s && *s != '\n' && *s != '\r')
3429 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);
3433 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);
3436 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3437 radius = bound(15, radius, 4096);
3438 VectorScale(color, (2.0f / (8388608.0f)), color);
3439 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3447 Con_Printf("invalid lights file \"%s\"\n", name);
3448 Mem_Free(lightsstring);
3452 // tyrlite/hmap2 light types in the delay field
3453 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3455 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3457 int entnum, style, islight, skin, pflags, effects, type, n;
3460 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3461 char key[256], value[MAX_INPUTLINE];
3463 if (r_refdef.worldmodel == NULL)
3465 Con_Print("No map loaded.\n");
3468 // try to load a .ent file first
3469 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3470 strlcat (key, ".ent", sizeof (key));
3471 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3472 // and if that is not found, fall back to the bsp file entity string
3474 data = r_refdef.worldmodel->brush.entities;
3477 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3479 type = LIGHTTYPE_MINUSX;
3480 origin[0] = origin[1] = origin[2] = 0;
3481 originhack[0] = originhack[1] = originhack[2] = 0;
3482 angles[0] = angles[1] = angles[2] = 0;
3483 color[0] = color[1] = color[2] = 1;
3484 light[0] = light[1] = light[2] = 1;light[3] = 300;
3485 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3495 if (!COM_ParseToken(&data, false))
3497 if (com_token[0] == '}')
3498 break; // end of entity
3499 if (com_token[0] == '_')
3500 strcpy(key, com_token + 1);
3502 strcpy(key, com_token);
3503 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3504 key[strlen(key)-1] = 0;
3505 if (!COM_ParseToken(&data, false))
3507 strcpy(value, com_token);
3509 // now that we have the key pair worked out...
3510 if (!strcmp("light", key))
3512 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3516 light[0] = vec[0] * (1.0f / 256.0f);
3517 light[1] = vec[0] * (1.0f / 256.0f);
3518 light[2] = vec[0] * (1.0f / 256.0f);
3524 light[0] = vec[0] * (1.0f / 255.0f);
3525 light[1] = vec[1] * (1.0f / 255.0f);
3526 light[2] = vec[2] * (1.0f / 255.0f);
3530 else if (!strcmp("delay", key))
3532 else if (!strcmp("origin", key))
3533 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3534 else if (!strcmp("angle", key))
3535 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3536 else if (!strcmp("angles", key))
3537 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3538 else if (!strcmp("color", key))
3539 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3540 else if (!strcmp("wait", key))
3541 fadescale = atof(value);
3542 else if (!strcmp("classname", key))
3544 if (!strncmp(value, "light", 5))
3547 if (!strcmp(value, "light_fluoro"))
3552 overridecolor[0] = 1;
3553 overridecolor[1] = 1;
3554 overridecolor[2] = 1;
3556 if (!strcmp(value, "light_fluorospark"))
3561 overridecolor[0] = 1;
3562 overridecolor[1] = 1;
3563 overridecolor[2] = 1;
3565 if (!strcmp(value, "light_globe"))
3570 overridecolor[0] = 1;
3571 overridecolor[1] = 0.8;
3572 overridecolor[2] = 0.4;
3574 if (!strcmp(value, "light_flame_large_yellow"))
3579 overridecolor[0] = 1;
3580 overridecolor[1] = 0.5;
3581 overridecolor[2] = 0.1;
3583 if (!strcmp(value, "light_flame_small_yellow"))
3588 overridecolor[0] = 1;
3589 overridecolor[1] = 0.5;
3590 overridecolor[2] = 0.1;
3592 if (!strcmp(value, "light_torch_small_white"))
3597 overridecolor[0] = 1;
3598 overridecolor[1] = 0.5;
3599 overridecolor[2] = 0.1;
3601 if (!strcmp(value, "light_torch_small_walltorch"))
3606 overridecolor[0] = 1;
3607 overridecolor[1] = 0.5;
3608 overridecolor[2] = 0.1;
3612 else if (!strcmp("style", key))
3613 style = atoi(value);
3614 else if (!strcmp("skin", key))
3615 skin = (int)atof(value);
3616 else if (!strcmp("pflags", key))
3617 pflags = (int)atof(value);
3618 else if (!strcmp("effects", key))
3619 effects = (int)atof(value);
3620 else if (r_refdef.worldmodel->type == mod_brushq3)
3622 if (!strcmp("scale", key))
3623 lightscale = atof(value);
3624 if (!strcmp("fade", key))
3625 fadescale = atof(value);
3630 if (lightscale <= 0)
3634 if (color[0] == color[1] && color[0] == color[2])
3636 color[0] *= overridecolor[0];
3637 color[1] *= overridecolor[1];
3638 color[2] *= overridecolor[2];
3640 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3641 color[0] = color[0] * light[0];
3642 color[1] = color[1] * light[1];
3643 color[2] = color[2] * light[2];
3646 case LIGHTTYPE_MINUSX:
3648 case LIGHTTYPE_RECIPX:
3650 VectorScale(color, (1.0f / 16.0f), color);
3652 case LIGHTTYPE_RECIPXX:
3654 VectorScale(color, (1.0f / 16.0f), color);
3657 case LIGHTTYPE_NONE:
3661 case LIGHTTYPE_MINUSXX:
3664 VectorAdd(origin, originhack, origin);
3666 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);
3669 Mem_Free(entfiledata);
3673 void R_Shadow_SetCursorLocationForView(void)
3676 vec3_t dest, endpos;
3678 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3679 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3680 if (trace.fraction < 1)
3682 dist = trace.fraction * r_editlights_cursordistance.value;
3683 push = r_editlights_cursorpushback.value;
3687 VectorMA(trace.endpos, push, r_viewforward, endpos);
3688 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3692 VectorClear( endpos );
3694 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3695 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3696 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3699 void R_Shadow_UpdateWorldLightSelection(void)
3701 if (r_editlights.integer)
3703 R_Shadow_SetCursorLocationForView();
3704 R_Shadow_SelectLightInView();
3705 R_Shadow_DrawLightSprites();
3708 R_Shadow_SelectLight(NULL);
3711 void R_Shadow_EditLights_Clear_f(void)
3713 R_Shadow_ClearWorldLights();
3716 void R_Shadow_EditLights_Reload_f(void)
3718 if (!r_refdef.worldmodel)
3720 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3721 R_Shadow_ClearWorldLights();
3722 R_Shadow_LoadWorldLights();
3723 if (r_shadow_worldlightchain == NULL)
3725 R_Shadow_LoadLightsFile();
3726 if (r_shadow_worldlightchain == NULL)
3727 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3731 void R_Shadow_EditLights_Save_f(void)
3733 if (!r_refdef.worldmodel)
3735 R_Shadow_SaveWorldLights();
3738 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3740 R_Shadow_ClearWorldLights();
3741 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3744 void R_Shadow_EditLights_ImportLightsFile_f(void)
3746 R_Shadow_ClearWorldLights();
3747 R_Shadow_LoadLightsFile();
3750 void R_Shadow_EditLights_Spawn_f(void)
3753 if (!r_editlights.integer)
3755 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3758 if (Cmd_Argc() != 1)
3760 Con_Print("r_editlights_spawn does not take parameters\n");
3763 color[0] = color[1] = color[2] = 1;
3764 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3767 void R_Shadow_EditLights_Edit_f(void)
3769 vec3_t origin, angles, color;
3770 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3771 int style, shadows, flags, normalmode, realtimemode;
3772 char cubemapname[MAX_INPUTLINE];
3773 if (!r_editlights.integer)
3775 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3778 if (!r_shadow_selectedlight)
3780 Con_Print("No selected light.\n");
3783 VectorCopy(r_shadow_selectedlight->origin, origin);
3784 VectorCopy(r_shadow_selectedlight->angles, angles);
3785 VectorCopy(r_shadow_selectedlight->color, color);
3786 radius = r_shadow_selectedlight->radius;
3787 style = r_shadow_selectedlight->style;
3788 if (r_shadow_selectedlight->cubemapname)
3789 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3792 shadows = r_shadow_selectedlight->shadow;
3793 corona = r_shadow_selectedlight->corona;
3794 coronasizescale = r_shadow_selectedlight->coronasizescale;
3795 ambientscale = r_shadow_selectedlight->ambientscale;
3796 diffusescale = r_shadow_selectedlight->diffusescale;
3797 specularscale = r_shadow_selectedlight->specularscale;
3798 flags = r_shadow_selectedlight->flags;
3799 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3800 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3801 if (!strcmp(Cmd_Argv(1), "origin"))
3803 if (Cmd_Argc() != 5)
3805 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3808 origin[0] = atof(Cmd_Argv(2));
3809 origin[1] = atof(Cmd_Argv(3));
3810 origin[2] = atof(Cmd_Argv(4));
3812 else if (!strcmp(Cmd_Argv(1), "originx"))
3814 if (Cmd_Argc() != 3)
3816 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3819 origin[0] = atof(Cmd_Argv(2));
3821 else if (!strcmp(Cmd_Argv(1), "originy"))
3823 if (Cmd_Argc() != 3)
3825 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3828 origin[1] = atof(Cmd_Argv(2));
3830 else if (!strcmp(Cmd_Argv(1), "originz"))
3832 if (Cmd_Argc() != 3)
3834 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3837 origin[2] = atof(Cmd_Argv(2));
3839 else if (!strcmp(Cmd_Argv(1), "move"))
3841 if (Cmd_Argc() != 5)
3843 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3846 origin[0] += atof(Cmd_Argv(2));
3847 origin[1] += atof(Cmd_Argv(3));
3848 origin[2] += atof(Cmd_Argv(4));
3850 else if (!strcmp(Cmd_Argv(1), "movex"))
3852 if (Cmd_Argc() != 3)
3854 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3857 origin[0] += atof(Cmd_Argv(2));
3859 else if (!strcmp(Cmd_Argv(1), "movey"))
3861 if (Cmd_Argc() != 3)
3863 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3866 origin[1] += atof(Cmd_Argv(2));
3868 else if (!strcmp(Cmd_Argv(1), "movez"))
3870 if (Cmd_Argc() != 3)
3872 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3875 origin[2] += atof(Cmd_Argv(2));
3877 else if (!strcmp(Cmd_Argv(1), "angles"))
3879 if (Cmd_Argc() != 5)
3881 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3884 angles[0] = atof(Cmd_Argv(2));
3885 angles[1] = atof(Cmd_Argv(3));
3886 angles[2] = atof(Cmd_Argv(4));
3888 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3890 if (Cmd_Argc() != 3)
3892 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3895 angles[0] = atof(Cmd_Argv(2));
3897 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3899 if (Cmd_Argc() != 3)
3901 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3904 angles[1] = atof(Cmd_Argv(2));
3906 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3908 if (Cmd_Argc() != 3)
3910 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3913 angles[2] = atof(Cmd_Argv(2));
3915 else if (!strcmp(Cmd_Argv(1), "color"))
3917 if (Cmd_Argc() != 5)
3919 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3922 color[0] = atof(Cmd_Argv(2));
3923 color[1] = atof(Cmd_Argv(3));
3924 color[2] = atof(Cmd_Argv(4));
3926 else if (!strcmp(Cmd_Argv(1), "radius"))
3928 if (Cmd_Argc() != 3)
3930 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3933 radius = atof(Cmd_Argv(2));
3935 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3937 if (Cmd_Argc() == 3)
3939 double scale = atof(Cmd_Argv(2));
3946 if (Cmd_Argc() != 5)
3948 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3951 color[0] *= atof(Cmd_Argv(2));
3952 color[1] *= atof(Cmd_Argv(3));
3953 color[2] *= atof(Cmd_Argv(4));
3956 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3958 if (Cmd_Argc() != 3)
3960 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3963 radius *= atof(Cmd_Argv(2));
3965 else if (!strcmp(Cmd_Argv(1), "style"))
3967 if (Cmd_Argc() != 3)
3969 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3972 style = atoi(Cmd_Argv(2));
3974 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3978 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3981 if (Cmd_Argc() == 3)
3982 strcpy(cubemapname, Cmd_Argv(2));
3986 else if (!strcmp(Cmd_Argv(1), "shadows"))
3988 if (Cmd_Argc() != 3)
3990 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3993 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3995 else if (!strcmp(Cmd_Argv(1), "corona"))
3997 if (Cmd_Argc() != 3)
3999 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4002 corona = atof(Cmd_Argv(2));
4004 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4006 if (Cmd_Argc() != 3)
4008 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4011 coronasizescale = atof(Cmd_Argv(2));
4013 else if (!strcmp(Cmd_Argv(1), "ambient"))
4015 if (Cmd_Argc() != 3)
4017 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4020 ambientscale = atof(Cmd_Argv(2));
4022 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4024 if (Cmd_Argc() != 3)
4026 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4029 diffusescale = atof(Cmd_Argv(2));
4031 else if (!strcmp(Cmd_Argv(1), "specular"))
4033 if (Cmd_Argc() != 3)
4035 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4038 specularscale = atof(Cmd_Argv(2));
4040 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4042 if (Cmd_Argc() != 3)
4044 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4047 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4049 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4051 if (Cmd_Argc() != 3)
4053 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4056 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4060 Con_Print("usage: r_editlights_edit [property] [value]\n");
4061 Con_Print("Selected light's properties:\n");
4062 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4063 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4064 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4065 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4066 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4067 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4068 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4069 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4070 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4071 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4072 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4073 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4074 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4075 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4078 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4079 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4082 void R_Shadow_EditLights_EditAll_f(void)
4086 if (!r_editlights.integer)
4088 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4092 for (light = r_shadow_worldlightchain;light;light = light->next)
4094 R_Shadow_SelectLight(light);
4095 R_Shadow_EditLights_Edit_f();
4099 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4101 int lightnumber, lightcount;
4105 if (!r_editlights.integer)
4111 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4112 if (light == r_shadow_selectedlight)
4113 lightnumber = lightcount;
4114 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;
4115 if (r_shadow_selectedlight == NULL)
4117 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4118 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;
4119 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;
4120 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;
4121 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4122 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4123 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4124 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;
4125 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4126 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4127 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4128 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4129 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4130 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;
4131 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;
4134 void R_Shadow_EditLights_ToggleShadow_f(void)
4136 if (!r_editlights.integer)
4138 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4141 if (!r_shadow_selectedlight)
4143 Con_Print("No selected light.\n");
4146 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);
4149 void R_Shadow_EditLights_ToggleCorona_f(void)
4151 if (!r_editlights.integer)
4153 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4156 if (!r_shadow_selectedlight)
4158 Con_Print("No selected light.\n");
4161 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);
4164 void R_Shadow_EditLights_Remove_f(void)
4166 if (!r_editlights.integer)
4168 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4171 if (!r_shadow_selectedlight)
4173 Con_Print("No selected light.\n");
4176 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4177 r_shadow_selectedlight = NULL;
4180 void R_Shadow_EditLights_Help_f(void)
4183 "Documentation on r_editlights system:\n"
4185 "r_editlights : enable/disable editing mode\n"
4186 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4187 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4188 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4189 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4190 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4192 "r_editlights_help : this help\n"
4193 "r_editlights_clear : remove all lights\n"
4194 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4195 "r_editlights_save : save to .rtlights file\n"
4196 "r_editlights_spawn : create a light with default settings\n"
4197 "r_editlights_edit command : edit selected light - more documentation below\n"
4198 "r_editlights_remove : remove selected light\n"
4199 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4200 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4201 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4203 "origin x y z : set light location\n"
4204 "originx x: set x component of light location\n"
4205 "originy y: set y component of light location\n"
4206 "originz z: set z component of light location\n"
4207 "move x y z : adjust light location\n"
4208 "movex x: adjust x component of light location\n"
4209 "movey y: adjust y component of light location\n"
4210 "movez z: adjust z component of light location\n"
4211 "angles x y z : set light angles\n"
4212 "anglesx x: set x component of light angles\n"
4213 "anglesy y: set y component of light angles\n"
4214 "anglesz z: set z component of light angles\n"
4215 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4216 "radius radius : set radius (size) of light\n"
4217 "colorscale grey : multiply color of light (1 does nothing)\n"
4218 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4219 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4220 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4221 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4222 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4223 "shadows 1/0 : turn on/off shadows\n"
4224 "corona n : set corona intensity\n"
4225 "coronasize n : set corona size (0-1)\n"
4226 "ambient n : set ambient intensity (0-1)\n"
4227 "diffuse n : set diffuse intensity (0-1)\n"
4228 "specular n : set specular intensity (0-1)\n"
4229 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4230 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4231 "<nothing> : print light properties to console\n"
4235 void R_Shadow_EditLights_CopyInfo_f(void)
4237 if (!r_editlights.integer)
4239 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4242 if (!r_shadow_selectedlight)
4244 Con_Print("No selected light.\n");
4247 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4248 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4249 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4250 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4251 if (r_shadow_selectedlight->cubemapname)
4252 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4254 r_shadow_bufferlight.cubemapname[0] = 0;
4255 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4256 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4257 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4258 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4259 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4260 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4261 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4264 void R_Shadow_EditLights_PasteInfo_f(void)
4266 if (!r_editlights.integer)
4268 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4271 if (!r_shadow_selectedlight)
4273 Con_Print("No selected light.\n");
4276 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);
4279 void R_Shadow_EditLights_Init(void)
4281 Cvar_RegisterVariable(&r_editlights);
4282 Cvar_RegisterVariable(&r_editlights_cursordistance);
4283 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4284 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4285 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4286 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4287 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4288 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4289 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4290 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4291 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4292 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4293 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4294 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4295 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4296 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4297 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4298 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4299 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4300 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);