3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadowstage_e
148 R_SHADOWSTAGE_STENCIL,
149 R_SHADOWSTAGE_STENCILTWOSIDE,
150 R_SHADOWSTAGE_LIGHT_VERTEX,
151 R_SHADOWSTAGE_LIGHT_DOT3,
152 R_SHADOWSTAGE_LIGHT_GLSL,
153 R_SHADOWSTAGE_VISIBLEVOLUMES,
154 R_SHADOWSTAGE_VISIBLELIGHTING,
158 r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
160 mempool_t *r_shadow_mempool;
162 int maxshadowelements;
176 int r_shadow_buffer_numleafpvsbytes;
177 qbyte *r_shadow_buffer_leafpvs;
178 int *r_shadow_buffer_leaflist;
180 int r_shadow_buffer_numsurfacepvsbytes;
181 qbyte *r_shadow_buffer_surfacepvs;
182 int *r_shadow_buffer_surfacelist;
184 rtexturepool_t *r_shadow_texturepool;
185 rtexture_t *r_shadow_attenuation2dtexture;
186 rtexture_t *r_shadow_attenuation3dtexture;
188 // lights are reloaded when this changes
189 char r_shadow_mapname[MAX_QPATH];
191 // used only for light filters (cubemaps)
192 rtexturepool_t *r_shadow_filters_texturepool;
194 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
195 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
196 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
197 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
198 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
199 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
200 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
201 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
202 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
203 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
204 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
205 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
206 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
207 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
208 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
209 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
210 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
211 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
212 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
213 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
214 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
215 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
216 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
217 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
218 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
219 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
220 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
221 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
222 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "0"};
223 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
224 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
225 cvar_t r_shadow_glsl_usehalffloat = {0, "r_shadow_glsl_usehalffloat", "0"};
226 cvar_t r_shadow_glsl_surfacenormalize = {0, "r_shadow_glsl_surfacenormalize", "1"};
227 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
228 cvar_t r_editlights = {0, "r_editlights", "0"};
229 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
230 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
231 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
232 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
233 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
235 float r_shadow_attenpower, r_shadow_attenscale;
237 rtlight_t *r_shadow_compilingrtlight;
238 dlight_t *r_shadow_worldlightchain;
239 dlight_t *r_shadow_selectedlight;
240 dlight_t r_shadow_bufferlight;
241 vec3_t r_editlights_cursorlocation;
243 rtexture_t *lighttextures[5];
245 extern int con_vislines;
247 typedef struct cubemapinfo_s
254 #define MAX_CUBEMAPS 256
255 static int numcubemaps;
256 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
258 #define SHADERPERMUTATION_SPECULAR (1<<0)
259 #define SHADERPERMUTATION_FOG (1<<1)
260 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
261 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
262 #define SHADERPERMUTATION_SURFACENORMALIZE (1<<4)
263 #define SHADERPERMUTATION_GEFORCEFX (1<<5)
264 #define SHADERPERMUTATION_COUNT (1<<6)
266 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
268 void R_Shadow_UncompileWorldLights(void);
269 void R_Shadow_ClearWorldLights(void);
270 void R_Shadow_SaveWorldLights(void);
271 void R_Shadow_LoadWorldLights(void);
272 void R_Shadow_LoadLightsFile(void);
273 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
274 void R_Shadow_EditLights_Reload_f(void);
275 void R_Shadow_ValidateCvars(void);
276 static void R_Shadow_MakeTextures(void);
277 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
279 const char *builtinshader_light_vert =
280 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
281 "// written by Forest 'LordHavoc' Hale\n"
283 "uniform vec3 LightPosition;\n"
285 "varying vec2 TexCoord;\n"
286 "varying vec3 CubeVector;\n"
287 "varying vec3 LightVector;\n"
289 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
290 "uniform vec3 EyePosition;\n"
291 "varying vec3 EyeVector;\n"
294 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
298 " // copy the surface texcoord\n"
299 " TexCoord = vec2(gl_TextureMatrix[0] * glMultiTexCoord0);\n"
301 " // transform vertex position into light attenuation/cubemap space\n"
302 " // (-1 to +1 across the light box)\n"
303 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
305 " // transform unnormalized light direction into tangent space\n"
306 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
307 " // normalize it per pixel)\n"
308 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
309 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
310 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
311 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
313 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
314 " // transform unnormalized eye direction into tangent space\n"
315 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
316 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
317 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
318 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
321 " // transform vertex to camera space, using ftransform to match non-VS\n"
323 " gl_Position = ftransform();\n"
327 const char *builtinshader_light_frag =
328 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
329 "// written by Forest 'LordHavoc' Hale\n"
331 "// use half floats on GEFORCEFX for math performance, otherwise don't\n"
332 "#ifndef GEFORCEFX\n"
333 "#define half float\n"
334 "#define hvec2 vec2\n"
335 "#define hvec3 vec3\n"
336 "#define hvec4 vec4\n"
339 "uniform hvec3 LightColor;\n"
340 "#ifdef USEOFFSETMAPPING\n"
341 "uniform half OffsetMapping_Scale;\n"
342 "uniform half OffsetMapping_Bias;\n"
344 "#ifdef USESPECULAR\n"
345 "uniform half SpecularPower;\n"
348 "uniform half FogRangeRecip;\n"
350 "uniform half AmbientScale;\n"
351 "uniform half DiffuseScale;\n"
352 "#ifdef USESPECULAR\n"
353 "uniform half SpecularScale;\n"
356 "uniform sampler2D Texture_Normal;\n"
357 "uniform sampler2D Texture_Color;\n"
358 "#ifdef USESPECULAR\n"
359 "uniform sampler2D Texture_Gloss;\n"
361 "#ifdef USECUBEFILTER\n"
362 "uniform samplerCube Texture_Cube;\n"
365 "uniform sampler2D Texture_FogMask;\n"
368 "varying vec2 TexCoord;\n"
369 "varying vec3 CubeVector;\n"
370 "varying vec3 LightVector;\n"
371 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
372 "varying vec3 EyeVector;\n"
379 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
380 " // center and sharp falloff at the edge, this is about the most efficient\n"
381 " // we can get away with as far as providing illumination.\n"
383 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
384 " // provide significant illumination, large = slow = pain.\n"
385 " half colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
389 " colorscale *= texture2D(Texture_FogMask, hvec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
392 "#ifdef USEOFFSETMAPPING\n"
393 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
394 " hvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
395 " hvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
396 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
397 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
398 "#define TexCoord TexCoordOffset\n"
401 " // get the surface normal\n"
402 "#ifdef SURFACENORMALIZE\n"
403 " hvec3 surfacenormal = normalize(hvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
405 " hvec3 surfacenormal = -1.0 + 2.0 * hvec3(texture2D(Texture_Normal, TexCoord));\n"
408 " // calculate shading\n"
409 " hvec3 diffusenormal = hvec3(normalize(LightVector));\n"
410 " hvec3 color = hvec3(texture2D(Texture_Color, TexCoord)) * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
411 "#ifdef USESPECULAR\n"
412 " hvec3 specularnormal = hvec3(normalize(diffusenormal + hvec3(normalize(EyeVector))));\n"
413 " color += hvec3(texture2D(Texture_Gloss, TexCoord)) * (SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower));\n"
416 "#ifdef USECUBEFILTER\n"
417 " // apply light cubemap filter\n"
418 " color *= hvec3(textureCube(Texture_Cube, CubeVector));\n"
421 " // calculate fragment color (apply light color and attenuation/fog scaling)\n"
422 " gl_FragColor = hvec4(color * LightColor * colorscale, 1);\n"
426 void r_shadow_start(void)
429 // use half float math where available (speed gain on NVIDIA GFFX and GF6)
430 if (gl_support_half_float)
431 Cvar_SetValue("r_shadow_glsl_usehalffloat", 1);
432 // allocate vertex processing arrays
434 r_shadow_attenuation2dtexture = NULL;
435 r_shadow_attenuation3dtexture = NULL;
436 r_shadow_texturepool = NULL;
437 r_shadow_filters_texturepool = NULL;
438 R_Shadow_ValidateCvars();
439 R_Shadow_MakeTextures();
440 maxshadowelements = 0;
441 shadowelements = NULL;
449 shadowmarklist = NULL;
451 r_shadow_buffer_numleafpvsbytes = 0;
452 r_shadow_buffer_leafpvs = NULL;
453 r_shadow_buffer_leaflist = NULL;
454 r_shadow_buffer_numsurfacepvsbytes = 0;
455 r_shadow_buffer_surfacepvs = NULL;
456 r_shadow_buffer_surfacelist = NULL;
457 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
458 r_shadow_program_light[i] = 0;
459 if (gl_support_fragment_shader)
461 char *vertstring, *fragstring;
462 int vertstrings_count;
463 int fragstrings_count;
464 const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
465 const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
466 vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false);
467 fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false);
468 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
470 vertstrings_count = 0;
471 fragstrings_count = 0;
472 if (i & SHADERPERMUTATION_SPECULAR)
474 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
475 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
477 if (i & SHADERPERMUTATION_FOG)
479 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
480 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
482 if (i & SHADERPERMUTATION_CUBEFILTER)
484 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
485 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
487 if (i & SHADERPERMUTATION_OFFSETMAPPING)
489 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
490 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
492 if (i & SHADERPERMUTATION_SURFACENORMALIZE)
494 vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
495 fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
497 if (i & SHADERPERMUTATION_GEFORCEFX)
499 vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
500 fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
502 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
503 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
504 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
505 if (!r_shadow_program_light[i])
507 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");
510 qglUseProgramObjectARB(r_shadow_program_light[i]);
511 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
512 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
513 if (i & SHADERPERMUTATION_SPECULAR)
515 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
517 if (i & SHADERPERMUTATION_CUBEFILTER)
519 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
521 if (i & SHADERPERMUTATION_FOG)
523 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
526 qglUseProgramObjectARB(0);
528 Mem_Free(fragstring);
530 Mem_Free(vertstring);
534 void r_shadow_shutdown(void)
537 R_Shadow_UncompileWorldLights();
538 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
540 if (r_shadow_program_light[i])
542 GL_Backend_FreeProgram(r_shadow_program_light[i]);
543 r_shadow_program_light[i] = 0;
547 r_shadow_attenuation2dtexture = NULL;
548 r_shadow_attenuation3dtexture = NULL;
549 R_FreeTexturePool(&r_shadow_texturepool);
550 R_FreeTexturePool(&r_shadow_filters_texturepool);
551 maxshadowelements = 0;
553 Mem_Free(shadowelements);
554 shadowelements = NULL;
557 Mem_Free(vertexupdate);
560 Mem_Free(vertexremap);
566 Mem_Free(shadowmark);
569 Mem_Free(shadowmarklist);
570 shadowmarklist = NULL;
572 r_shadow_buffer_numleafpvsbytes = 0;
573 if (r_shadow_buffer_leafpvs)
574 Mem_Free(r_shadow_buffer_leafpvs);
575 r_shadow_buffer_leafpvs = NULL;
576 if (r_shadow_buffer_leaflist)
577 Mem_Free(r_shadow_buffer_leaflist);
578 r_shadow_buffer_leaflist = NULL;
579 r_shadow_buffer_numsurfacepvsbytes = 0;
580 if (r_shadow_buffer_surfacepvs)
581 Mem_Free(r_shadow_buffer_surfacepvs);
582 r_shadow_buffer_surfacepvs = NULL;
583 if (r_shadow_buffer_surfacelist)
584 Mem_Free(r_shadow_buffer_surfacelist);
585 r_shadow_buffer_surfacelist = NULL;
588 void r_shadow_newmap(void)
592 void R_Shadow_Help_f(void)
595 "Documentation on r_shadow system:\n"
597 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
598 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
599 "r_shadow_debuglight : render only this light number (-1 = all)\n"
600 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
601 "r_shadow_gloss2intensity : brightness of forced gloss\n"
602 "r_shadow_glossintensity : brightness of textured gloss\n"
603 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
604 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
605 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
606 "r_shadow_portallight : use portal visibility for static light precomputation\n"
607 "r_shadow_projectdistance : shadow volume projection distance\n"
608 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
609 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
610 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
611 "r_shadow_realtime_world : use high quality world lighting mode\n"
612 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
613 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
614 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
615 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
616 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
617 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
618 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
619 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
620 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
621 "r_shadow_glsl_usehalffloat : use lower quality lighting\n"
622 "r_shadow_glsl_surfacenormalize : makes bumpmapping slightly higher quality\n"
623 "r_shadow_scissor : use scissor optimization\n"
624 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
625 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
626 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
627 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
628 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
629 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
631 "r_shadow_help : this help\n"
635 void R_Shadow_Init(void)
637 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
638 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
639 Cvar_RegisterVariable(&r_shadow_debuglight);
640 Cvar_RegisterVariable(&r_shadow_gloss);
641 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
642 Cvar_RegisterVariable(&r_shadow_glossintensity);
643 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
644 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
645 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
646 Cvar_RegisterVariable(&r_shadow_portallight);
647 Cvar_RegisterVariable(&r_shadow_projectdistance);
648 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
649 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
651 Cvar_RegisterVariable(&r_shadow_realtime_world);
652 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
653 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
657 Cvar_RegisterVariable(&r_shadow_scissor);
658 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
659 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
660 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
661 Cvar_RegisterVariable(&r_shadow_texture3d);
662 Cvar_RegisterVariable(&r_shadow_visiblelighting);
663 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
664 Cvar_RegisterVariable(&r_shadow_glsl);
665 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
666 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
667 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
668 Cvar_RegisterVariable(&r_shadow_glsl_usehalffloat);
669 Cvar_RegisterVariable(&r_shadow_glsl_surfacenormalize);
670 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
671 if (gamemode == GAME_TENEBRAE)
673 Cvar_SetValue("r_shadow_gloss", 2);
674 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
676 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
677 R_Shadow_EditLights_Init();
678 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
679 r_shadow_worldlightchain = NULL;
680 maxshadowelements = 0;
681 shadowelements = NULL;
689 shadowmarklist = NULL;
691 r_shadow_buffer_numleafpvsbytes = 0;
692 r_shadow_buffer_leafpvs = NULL;
693 r_shadow_buffer_leaflist = NULL;
694 r_shadow_buffer_numsurfacepvsbytes = 0;
695 r_shadow_buffer_surfacepvs = NULL;
696 r_shadow_buffer_surfacelist = NULL;
697 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
700 matrix4x4_t matrix_attenuationxyz =
703 {0.5, 0.0, 0.0, 0.5},
704 {0.0, 0.5, 0.0, 0.5},
705 {0.0, 0.0, 0.5, 0.5},
710 matrix4x4_t matrix_attenuationz =
713 {0.0, 0.0, 0.5, 0.5},
714 {0.0, 0.0, 0.0, 0.5},
715 {0.0, 0.0, 0.0, 0.5},
720 int *R_Shadow_ResizeShadowElements(int numtris)
722 // make sure shadowelements is big enough for this volume
723 if (maxshadowelements < numtris * 24)
725 maxshadowelements = numtris * 24;
727 Mem_Free(shadowelements);
728 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
730 return shadowelements;
733 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
735 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
736 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
737 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
739 if (r_shadow_buffer_leafpvs)
740 Mem_Free(r_shadow_buffer_leafpvs);
741 if (r_shadow_buffer_leaflist)
742 Mem_Free(r_shadow_buffer_leaflist);
743 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
744 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
745 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
747 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
749 if (r_shadow_buffer_surfacepvs)
750 Mem_Free(r_shadow_buffer_surfacepvs);
751 if (r_shadow_buffer_surfacelist)
752 Mem_Free(r_shadow_buffer_surfacelist);
753 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
754 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
755 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
759 void R_Shadow_PrepareShadowMark(int numtris)
761 // make sure shadowmark is big enough for this volume
762 if (maxshadowmark < numtris)
764 maxshadowmark = numtris;
766 Mem_Free(shadowmark);
768 Mem_Free(shadowmarklist);
769 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
770 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
774 // if shadowmarkcount wrapped we clear the array and adjust accordingly
775 if (shadowmarkcount == 0)
778 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
783 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)
786 int outtriangles = 0, outvertices = 0;
790 if (maxvertexupdate < innumvertices)
792 maxvertexupdate = innumvertices;
794 Mem_Free(vertexupdate);
796 Mem_Free(vertexremap);
797 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
798 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
802 if (vertexupdatenum == 0)
805 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
806 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
809 for (i = 0;i < numshadowmarktris;i++)
810 shadowmark[shadowmarktris[i]] = shadowmarkcount;
812 for (i = 0;i < numshadowmarktris;i++)
814 element = inelement3i + shadowmarktris[i] * 3;
815 // make sure the vertices are created
816 for (j = 0;j < 3;j++)
818 if (vertexupdate[element[j]] != vertexupdatenum)
820 float ratio, direction[3];
821 vertexupdate[element[j]] = vertexupdatenum;
822 vertexremap[element[j]] = outvertices;
823 vertex = invertex3f + element[j] * 3;
824 // project one copy of the vertex to the sphere radius of the light
825 // (FIXME: would projecting it to the light box be better?)
826 VectorSubtract(vertex, projectorigin, direction);
827 ratio = projectdistance / VectorLength(direction);
828 VectorCopy(vertex, outvertex3f);
829 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
836 for (i = 0;i < numshadowmarktris;i++)
838 int remappedelement[3];
840 const int *neighbortriangle;
842 markindex = shadowmarktris[i] * 3;
843 element = inelement3i + markindex;
844 neighbortriangle = inneighbor3i + markindex;
845 // output the front and back triangles
846 outelement3i[0] = vertexremap[element[0]];
847 outelement3i[1] = vertexremap[element[1]];
848 outelement3i[2] = vertexremap[element[2]];
849 outelement3i[3] = vertexremap[element[2]] + 1;
850 outelement3i[4] = vertexremap[element[1]] + 1;
851 outelement3i[5] = vertexremap[element[0]] + 1;
855 // output the sides (facing outward from this triangle)
856 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
858 remappedelement[0] = vertexremap[element[0]];
859 remappedelement[1] = vertexremap[element[1]];
860 outelement3i[0] = remappedelement[1];
861 outelement3i[1] = remappedelement[0];
862 outelement3i[2] = remappedelement[0] + 1;
863 outelement3i[3] = remappedelement[1];
864 outelement3i[4] = remappedelement[0] + 1;
865 outelement3i[5] = remappedelement[1] + 1;
870 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
872 remappedelement[1] = vertexremap[element[1]];
873 remappedelement[2] = vertexremap[element[2]];
874 outelement3i[0] = remappedelement[2];
875 outelement3i[1] = remappedelement[1];
876 outelement3i[2] = remappedelement[1] + 1;
877 outelement3i[3] = remappedelement[2];
878 outelement3i[4] = remappedelement[1] + 1;
879 outelement3i[5] = remappedelement[2] + 1;
884 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
886 remappedelement[0] = vertexremap[element[0]];
887 remappedelement[2] = vertexremap[element[2]];
888 outelement3i[0] = remappedelement[0];
889 outelement3i[1] = remappedelement[2];
890 outelement3i[2] = remappedelement[2] + 1;
891 outelement3i[3] = remappedelement[0];
892 outelement3i[4] = remappedelement[2] + 1;
893 outelement3i[5] = remappedelement[0] + 1;
900 *outnumvertices = outvertices;
904 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)
907 if (projectdistance < 0.1)
909 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
912 if (!numverts || !nummarktris)
914 // make sure shadowelements is big enough for this volume
915 if (maxshadowelements < nummarktris * 24)
916 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
917 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
918 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
921 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)
926 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
928 tend = firsttriangle + numtris;
929 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
930 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
931 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
933 // surface box entirely inside light box, no box cull
934 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
935 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
936 shadowmarklist[numshadowmark++] = t;
940 // surface box not entirely inside light box, cull each triangle
941 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
943 v[0] = invertex3f + e[0] * 3;
944 v[1] = invertex3f + e[1] * 3;
945 v[2] = invertex3f + e[2] * 3;
946 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
947 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
948 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
949 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
950 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
951 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
952 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
953 shadowmarklist[numshadowmark++] = t;
958 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
961 if (r_shadow_compilingrtlight)
963 // if we're compiling an rtlight, capture the mesh
964 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
967 memset(&m, 0, sizeof(m));
968 m.pointer_vertex = vertex3f;
970 GL_LockArrays(0, numvertices);
971 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
973 // decrement stencil if backface is behind depthbuffer
974 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
975 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
976 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
978 c_rt_shadowtris += numtriangles;
979 // increment stencil if frontface is behind depthbuffer
980 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
981 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
983 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
985 c_rt_shadowtris += numtriangles;
989 static void R_Shadow_MakeTextures(void)
992 float v[3], intensity;
994 R_FreeTexturePool(&r_shadow_texturepool);
995 r_shadow_texturepool = R_AllocTexturePool();
996 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
997 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
998 #define ATTEN2DSIZE 64
999 #define ATTEN3DSIZE 32
1000 data = Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
1001 for (y = 0;y < ATTEN2DSIZE;y++)
1003 for (x = 0;x < ATTEN2DSIZE;x++)
1005 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1006 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1008 intensity = 1.0f - sqrt(DotProduct(v, v));
1010 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1011 d = bound(0, intensity, 255);
1012 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1013 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1014 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1015 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1018 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1019 if (r_shadow_texture3d.integer)
1021 for (z = 0;z < ATTEN3DSIZE;z++)
1023 for (y = 0;y < ATTEN3DSIZE;y++)
1025 for (x = 0;x < ATTEN3DSIZE;x++)
1027 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1028 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1029 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1030 intensity = 1.0f - sqrt(DotProduct(v, v));
1032 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1033 d = bound(0, intensity, 255);
1034 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1035 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1036 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1037 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1041 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1046 void R_Shadow_ValidateCvars(void)
1048 if (r_shadow_texture3d.integer && !gl_texture3d)
1049 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1050 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1051 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1054 // light currently being rendered
1055 rtlight_t *r_shadow_rtlight;
1056 // light filter cubemap being used by the light
1057 static rtexture_t *r_shadow_lightcubemap;
1059 // this is the location of the eye in entity space
1060 static vec3_t r_shadow_entityeyeorigin;
1061 // this is the location of the light in entity space
1062 static vec3_t r_shadow_entitylightorigin;
1063 // this transforms entity coordinates to light filter cubemap coordinates
1064 // (also often used for other purposes)
1065 static matrix4x4_t r_shadow_entitytolight;
1066 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
1067 // of attenuation texturing in full 3D (Z result often ignored)
1068 static matrix4x4_t r_shadow_entitytoattenuationxyz;
1069 // this transforms only the Z to S, and T is always 0.5
1070 static matrix4x4_t r_shadow_entitytoattenuationz;
1071 // rtlight->color * r_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
1072 static vec3_t r_shadow_entitylightcolor;
1074 static int r_shadow_lightpermutation;
1075 static int r_shadow_lightprog;
1077 void R_Shadow_Stage_Begin(void)
1081 R_Shadow_ValidateCvars();
1083 if (!r_shadow_attenuation2dtexture
1084 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1085 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1086 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1087 R_Shadow_MakeTextures();
1089 memset(&m, 0, sizeof(m));
1090 GL_BlendFunc(GL_ONE, GL_ZERO);
1091 GL_DepthMask(false);
1094 GL_Color(0, 0, 0, 1);
1095 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1096 qglEnable(GL_CULL_FACE);
1097 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1098 r_shadowstage = R_SHADOWSTAGE_NONE;
1101 void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
1103 r_shadow_rtlight = rtlight;
1106 void R_Shadow_Stage_Reset(void)
1109 if (gl_support_stenciltwoside)
1110 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1111 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
1113 qglUseProgramObjectARB(0);
1114 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
1115 qglBegin(GL_TRIANGLES);
1119 memset(&m, 0, sizeof(m));
1123 void R_Shadow_Stage_StencilShadowVolumes(void)
1125 R_Shadow_Stage_Reset();
1126 GL_Color(1, 1, 1, 1);
1127 GL_ColorMask(0, 0, 0, 0);
1128 GL_BlendFunc(GL_ONE, GL_ZERO);
1129 GL_DepthMask(false);
1131 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1132 //if (r_shadow_shadow_polygonoffset.value != 0)
1134 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1135 // qglEnable(GL_POLYGON_OFFSET_FILL);
1138 // qglDisable(GL_POLYGON_OFFSET_FILL);
1139 qglDepthFunc(GL_LESS);
1140 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1141 qglEnable(GL_STENCIL_TEST);
1142 qglStencilFunc(GL_ALWAYS, 128, ~0);
1143 if (gl_ext_stenciltwoside.integer)
1145 r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
1146 qglDisable(GL_CULL_FACE);
1147 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1148 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1150 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1151 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1153 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1157 r_shadowstage = R_SHADOWSTAGE_STENCIL;
1158 qglEnable(GL_CULL_FACE);
1160 // this is changed by every shadow render so its value here is unimportant
1161 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1163 GL_Clear(GL_STENCIL_BUFFER_BIT);
1167 void R_Shadow_Stage_Lighting(int stenciltest)
1170 R_Shadow_Stage_Reset();
1171 GL_BlendFunc(GL_ONE, GL_ONE);
1172 GL_DepthMask(false);
1174 qglPolygonOffset(0, 0);
1175 //qglDisable(GL_POLYGON_OFFSET_FILL);
1176 GL_Color(1, 1, 1, 1);
1177 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1178 qglDepthFunc(GL_EQUAL);
1179 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1180 qglEnable(GL_CULL_FACE);
1181 if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
1182 qglEnable(GL_STENCIL_TEST);
1184 qglDisable(GL_STENCIL_TEST);
1186 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1187 // only draw light where this geometry was already rendered AND the
1188 // stencil is 128 (values other than this mean shadow)
1189 qglStencilFunc(GL_EQUAL, 128, ~0);
1190 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1192 r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
1193 memset(&m, 0, sizeof(m));
1194 m.pointer_vertex = varray_vertex3f;
1195 m.pointer_texcoord[0] = varray_texcoord2f[0];
1196 m.pointer_texcoord3f[1] = varray_svector3f;
1197 m.pointer_texcoord3f[2] = varray_tvector3f;
1198 m.pointer_texcoord3f[3] = varray_normal3f;
1199 m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
1200 m.tex[1] = R_GetTexture(r_texture_white); // diffuse
1201 m.tex[2] = R_GetTexture(r_texture_white); // gloss
1202 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
1203 // TODO: support fog (after renderer is converted to texture fog)
1204 m.tex[4] = R_GetTexture(r_texture_white); // fog
1205 //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
1207 GL_BlendFunc(GL_ONE, GL_ONE);
1208 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1210 r_shadow_lightpermutation = 0;
1211 // only add a feature to the permutation if that permutation exists
1212 // (otherwise it might end up not using a shader at all, which looks
1213 // worse than using less features)
1214 if (r_shadow_rtlight->specularscale && r_shadow_gloss.integer >= 1 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
1215 r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
1216 //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
1217 // r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
1218 if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
1219 r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
1220 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
1221 r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
1222 if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
1223 r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
1224 if (r_shadow_glsl_usehalffloat.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
1225 r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
1226 r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
1227 qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
1228 // TODO: support fog (after renderer is converted to texture fog)
1229 if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
1231 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
1233 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
1234 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
1235 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1237 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
1238 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
1240 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1241 //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1242 //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1244 // qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1246 if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
1248 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1249 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1252 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1253 r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
1255 r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
1258 void R_Shadow_Stage_VisibleShadowVolumes(void)
1260 R_Shadow_Stage_Reset();
1261 GL_BlendFunc(GL_ONE, GL_ONE);
1262 GL_DepthMask(false);
1263 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
1264 qglPolygonOffset(0, 0);
1265 GL_Color(0.0, 0.0125, 0.1, 1);
1266 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1267 qglDepthFunc(GL_GEQUAL);
1268 qglCullFace(GL_FRONT); // this culls back
1269 qglDisable(GL_CULL_FACE);
1270 qglDisable(GL_STENCIL_TEST);
1271 r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
1274 void R_Shadow_Stage_VisibleLighting(int stenciltest)
1276 R_Shadow_Stage_Reset();
1277 GL_BlendFunc(GL_ONE, GL_ONE);
1278 GL_DepthMask(false);
1279 GL_DepthTest(r_shadow_visiblelighting.integer < 2);
1280 qglPolygonOffset(0, 0);
1281 GL_Color(0.1, 0.0125, 0, 1);
1282 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1283 qglDepthFunc(GL_EQUAL);
1284 qglCullFace(GL_FRONT); // this culls back
1285 qglEnable(GL_CULL_FACE);
1287 qglEnable(GL_STENCIL_TEST);
1289 qglDisable(GL_STENCIL_TEST);
1290 r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
1293 void R_Shadow_Stage_End(void)
1295 R_Shadow_Stage_Reset();
1296 R_Shadow_Stage_ActiveLight(NULL);
1297 GL_BlendFunc(GL_ONE, GL_ZERO);
1300 qglPolygonOffset(0, 0);
1301 //qglDisable(GL_POLYGON_OFFSET_FILL);
1302 GL_Color(1, 1, 1, 1);
1303 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1304 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1305 qglDepthFunc(GL_LEQUAL);
1306 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1307 qglDisable(GL_STENCIL_TEST);
1308 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1309 if (gl_support_stenciltwoside)
1310 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1312 qglStencilFunc(GL_ALWAYS, 128, ~0);
1313 r_shadowstage = R_SHADOWSTAGE_NONE;
1316 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1318 int i, ix1, iy1, ix2, iy2;
1319 float x1, y1, x2, y2;
1322 mplane_t planes[11];
1323 float vertex3f[256*3];
1325 // if view is inside the light box, just say yes it's visible
1326 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1328 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1332 // create a temporary brush describing the area the light can affect in worldspace
1333 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1334 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1335 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1336 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1337 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1338 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1339 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1340 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1341 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1342 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1343 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1345 // turn the brush into a mesh
1346 memset(&mesh, 0, sizeof(rmesh_t));
1347 mesh.maxvertices = 256;
1348 mesh.vertex3f = vertex3f;
1349 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1350 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1352 // if that mesh is empty, the light is not visible at all
1353 if (!mesh.numvertices)
1356 if (!r_shadow_scissor.integer)
1359 // if that mesh is not empty, check what area of the screen it covers
1360 x1 = y1 = x2 = y2 = 0;
1362 for (i = 0;i < mesh.numvertices;i++)
1364 VectorCopy(mesh.vertex3f + i * 3, v);
1365 GL_TransformToScreen(v, v2);
1366 //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]);
1369 if (x1 > v2[0]) x1 = v2[0];
1370 if (x2 < v2[0]) x2 = v2[0];
1371 if (y1 > v2[1]) y1 = v2[1];
1372 if (y2 < v2[1]) y2 = v2[1];
1381 // now convert the scissor rectangle to integer screen coordinates
1386 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1388 // clamp it to the screen
1389 if (ix1 < r_view_x) ix1 = r_view_x;
1390 if (iy1 < r_view_y) iy1 = r_view_y;
1391 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1392 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1394 // if it is inside out, it's not visible
1395 if (ix2 <= ix1 || iy2 <= iy1)
1398 // the light area is visible, set up the scissor rectangle
1399 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1400 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1401 //qglEnable(GL_SCISSOR_TEST);
1406 extern float *rsurface_vertex3f;
1407 extern float *rsurface_svector3f;
1408 extern float *rsurface_tvector3f;
1409 extern float *rsurface_normal3f;
1410 extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
1412 static void R_Shadow_VertexShadingWithXYZAttenuation(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1414 int numverts = surface->num_vertices;
1415 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1416 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1417 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1418 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1419 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1421 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1422 if ((dist = DotProduct(v, v)) < 1)
1425 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1426 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1427 if ((dot = DotProduct(n, v)) > 0)
1429 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1430 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
1431 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
1432 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
1436 color4f[0] = ambientcolor[0] * distintensity - reduce;
1437 color4f[1] = ambientcolor[1] * distintensity - reduce;
1438 color4f[2] = ambientcolor[2] * distintensity - reduce;
1440 color4f[0] = bound(0, color4f[0], 1);
1441 color4f[1] = bound(0, color4f[1], 1);
1442 color4f[2] = bound(0, color4f[2], 1);
1445 VectorClear(color4f);
1450 static void R_Shadow_VertexShadingWithZAttenuation(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1452 int numverts = surface->num_vertices;
1453 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1454 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1455 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1456 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1457 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1459 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1460 if ((dist = fabs(v[2])) < 1)
1462 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1463 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1464 if ((dot = DotProduct(n, v)) > 0)
1466 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1467 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
1468 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
1469 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
1473 color4f[0] = ambientcolor[0] * distintensity - reduce;
1474 color4f[1] = ambientcolor[1] * distintensity - reduce;
1475 color4f[2] = ambientcolor[2] * distintensity - reduce;
1477 color4f[0] = bound(0, color4f[0], 1);
1478 color4f[1] = bound(0, color4f[1], 1);
1479 color4f[2] = bound(0, color4f[2], 1);
1482 VectorClear(color4f);
1487 static void R_Shadow_VertexShading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
1489 int numverts = surface->num_vertices;
1490 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1491 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1492 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1493 float dot, shadeintensity, v[3], n[3];
1494 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1496 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1497 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1498 if ((dot = DotProduct(n, v)) > 0)
1500 shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1501 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) - reduce;
1502 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) - reduce;
1503 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) - reduce;
1504 color4f[0] = bound(0, color4f[0], 1);
1505 color4f[1] = bound(0, color4f[1], 1);
1506 color4f[2] = bound(0, color4f[2], 1);
1509 VectorClear(color4f);
1514 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1515 #define USETEXMATRIX
1517 #ifndef USETEXMATRIX
1518 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1519 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1520 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1524 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1525 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1526 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1533 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1537 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1538 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1546 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)
1550 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1552 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1553 // the cubemap normalizes this for us
1554 out3f[0] = DotProduct(svector3f, lightdir);
1555 out3f[1] = DotProduct(tvector3f, lightdir);
1556 out3f[2] = DotProduct(normal3f, lightdir);
1560 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)
1563 float lightdir[3], eyedir[3], halfdir[3];
1564 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1566 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1567 VectorNormalize(lightdir);
1568 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1569 VectorNormalize(eyedir);
1570 VectorAdd(lightdir, eyedir, halfdir);
1571 // the cubemap normalizes this for us
1572 out3f[0] = DotProduct(svector3f, halfdir);
1573 out3f[1] = DotProduct(tvector3f, halfdir);
1574 out3f[2] = DotProduct(normal3f, halfdir);
1578 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
1580 // used to display how many times a surface is lit for level design purposes
1581 int surfacelistindex;
1583 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1584 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1585 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1586 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1587 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1588 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1589 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1590 if (!doambientbase && !dodiffusebase && !doambientpants && !dodiffusepants && !doambientshirt && !dodiffuseshirt && !dospecular)
1592 GL_Color(0.1, 0.025, 0, 1);
1593 memset(&m, 0, sizeof(m));
1595 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1597 const msurface_t *surface = surfacelist[surfacelistindex];
1598 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1599 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1600 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
1601 GL_LockArrays(0, 0);
1605 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
1607 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1608 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 //qboolean dowatershader = (texture->currentmaterialflags & MATERIALFLAG_WATER) && r_watershader.value;
1617 // TODO: add direct pants/shirt rendering
1618 if (doambientpants || dodiffusepants)
1619 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
1620 if (doambientshirt || dodiffuseshirt)
1621 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
1622 if (!doambientbase && !dodiffusebase && !dospecular)
1624 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
1625 R_Mesh_TexBind(0, R_GetTexture(normalmaptexture));
1626 R_Mesh_TexBind(1, R_GetTexture(basetexture));
1627 R_Mesh_TexBind(2, R_GetTexture(glosstexture));
1628 if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
1630 qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
1632 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1633 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1635 const msurface_t *surface = surfacelist[surfacelistindex];
1636 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1637 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1638 if (!rsurface_svector3f)
1640 rsurface_svector3f = varray_svector3f;
1641 rsurface_tvector3f = varray_tvector3f;
1642 rsurface_normal3f = varray_normal3f;
1643 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);
1645 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1646 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1647 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1648 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1649 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1650 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1652 c_rt_lighttris += surface->num_triangles;
1653 GL_LockArrays(0, 0);
1657 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
1659 // ARB path (any Geforce, any Radeon)
1660 int surfacelistindex;
1662 float color2[3], colorscale;
1664 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1665 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
1666 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1667 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
1668 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1669 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
1670 qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
1671 // TODO: add direct pants/shirt rendering
1672 if (doambientpants || dodiffusepants)
1673 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
1674 if (doambientshirt || dodiffuseshirt)
1675 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
1676 if (!doambientbase && !dodiffusebase && !dospecular)
1678 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1680 const msurface_t *surface = surfacelist[surfacelistindex];
1681 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1682 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1683 if (!rsurface_svector3f)
1685 rsurface_svector3f = varray_svector3f;
1686 rsurface_tvector3f = varray_tvector3f;
1687 rsurface_normal3f = varray_normal3f;
1688 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);
1693 colorscale = r_shadow_rtlight->ambientscale;
1694 // colorscale accounts for how much we multiply the brightness
1697 // mult is how many times the final pass of the lighting will be
1698 // performed to get more brightness than otherwise possible.
1700 // Limit mult to 64 for sanity sake.
1701 if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1703 // 3 3D combine path (Geforce3, Radeon 8500)
1704 memset(&m, 0, sizeof(m));
1705 m.pointer_vertex = rsurface_vertex3f;
1706 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1708 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1709 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1711 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1712 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1714 m.tex[1] = R_GetTexture(basetexture);
1715 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1716 m.texmatrix[1] = texture->currenttexmatrix;
1717 m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
1719 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1720 m.texmatrix[2] = r_shadow_entitytolight;
1722 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1723 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1725 GL_BlendFunc(GL_ONE, GL_ONE);
1727 else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1729 // 2 3D combine path (Geforce3, original Radeon)
1730 memset(&m, 0, sizeof(m));
1731 m.pointer_vertex = rsurface_vertex3f;
1732 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1734 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1735 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1737 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1738 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1740 m.tex[1] = R_GetTexture(basetexture);
1741 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1742 m.texmatrix[1] = texture->currenttexmatrix;
1743 GL_BlendFunc(GL_ONE, GL_ONE);
1745 else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
1747 // 4 2D combine path (Geforce3, Radeon 8500)
1748 memset(&m, 0, sizeof(m));
1749 m.pointer_vertex = rsurface_vertex3f;
1750 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1752 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1753 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1755 m.pointer_texcoord[0] = varray_texcoord2f[0];
1756 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1758 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1760 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1761 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1763 m.pointer_texcoord[1] = varray_texcoord2f[1];
1764 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1766 m.tex[2] = R_GetTexture(basetexture);
1767 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1768 m.texmatrix[2] = texture->currenttexmatrix;
1769 if (r_shadow_lightcubemap != r_texture_whitecube)
1771 m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
1773 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1774 m.texmatrix[3] = r_shadow_entitytolight;
1776 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1777 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1780 GL_BlendFunc(GL_ONE, GL_ONE);
1782 else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
1784 // 3 2D combine path (Geforce3, original Radeon)
1785 memset(&m, 0, sizeof(m));
1786 m.pointer_vertex = rsurface_vertex3f;
1787 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1789 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1790 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1792 m.pointer_texcoord[0] = varray_texcoord2f[0];
1793 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1795 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1797 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1798 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1800 m.pointer_texcoord[1] = varray_texcoord2f[1];
1801 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1803 m.tex[2] = R_GetTexture(basetexture);
1804 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1805 m.texmatrix[2] = texture->currenttexmatrix;
1806 GL_BlendFunc(GL_ONE, GL_ONE);
1810 // 2/2/2 2D combine path (any dot3 card)
1811 memset(&m, 0, sizeof(m));
1812 m.pointer_vertex = rsurface_vertex3f;
1813 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1815 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1816 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1818 m.pointer_texcoord[0] = varray_texcoord2f[0];
1819 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1821 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1823 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1824 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1826 m.pointer_texcoord[1] = varray_texcoord2f[1];
1827 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1830 GL_ColorMask(0,0,0,1);
1831 GL_BlendFunc(GL_ONE, GL_ZERO);
1832 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1833 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1834 GL_LockArrays(0, 0);
1836 c_rt_lighttris += surface->num_triangles;
1838 memset(&m, 0, sizeof(m));
1839 m.pointer_vertex = rsurface_vertex3f;
1840 m.tex[0] = R_GetTexture(basetexture);
1841 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1842 m.texmatrix[0] = texture->currenttexmatrix;
1843 if (r_shadow_lightcubemap != r_texture_whitecube)
1845 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1847 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1848 m.texmatrix[1] = r_shadow_entitytolight;
1850 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1851 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1854 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1856 // this final code is shared
1858 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1859 VectorScale(lightcolorbase, colorscale, color2);
1860 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1861 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1863 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1864 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1866 c_rt_lighttris += surface->num_triangles;
1868 GL_LockArrays(0, 0);
1873 colorscale = r_shadow_rtlight->diffusescale;
1874 // colorscale accounts for how much we multiply the brightness
1877 // mult is how many times the final pass of the lighting will be
1878 // performed to get more brightness than otherwise possible.
1880 // Limit mult to 64 for sanity sake.
1881 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1883 // 3/2 3D combine path (Geforce3, Radeon 8500)
1884 memset(&m, 0, sizeof(m));
1885 m.pointer_vertex = rsurface_vertex3f;
1886 m.tex[0] = R_GetTexture(normalmaptexture);
1887 m.texcombinergb[0] = GL_REPLACE;
1888 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1889 m.texmatrix[0] = texture->currenttexmatrix;
1890 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1891 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1892 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1893 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);
1894 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1896 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1897 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1899 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1900 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1903 GL_ColorMask(0,0,0,1);
1904 GL_BlendFunc(GL_ONE, GL_ZERO);
1905 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1906 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1907 GL_LockArrays(0, 0);
1909 c_rt_lighttris += surface->num_triangles;
1911 memset(&m, 0, sizeof(m));
1912 m.pointer_vertex = rsurface_vertex3f;
1913 m.tex[0] = R_GetTexture(basetexture);
1914 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1915 m.texmatrix[0] = texture->currenttexmatrix;
1916 if (r_shadow_lightcubemap != r_texture_whitecube)
1918 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1920 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1921 m.texmatrix[1] = r_shadow_entitytolight;
1923 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1924 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1927 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1929 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
1931 // 1/2/2 3D combine path (original Radeon)
1932 memset(&m, 0, sizeof(m));
1933 m.pointer_vertex = rsurface_vertex3f;
1934 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1936 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1937 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1939 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1940 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1943 GL_ColorMask(0,0,0,1);
1944 GL_BlendFunc(GL_ONE, GL_ZERO);
1945 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1946 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1947 GL_LockArrays(0, 0);
1949 c_rt_lighttris += surface->num_triangles;
1951 memset(&m, 0, sizeof(m));
1952 m.pointer_vertex = rsurface_vertex3f;
1953 m.tex[0] = R_GetTexture(normalmaptexture);
1954 m.texcombinergb[0] = GL_REPLACE;
1955 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1956 m.texmatrix[0] = texture->currenttexmatrix;
1957 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1958 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1959 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1960 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);
1962 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1963 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1964 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1965 GL_LockArrays(0, 0);
1967 c_rt_lighttris += surface->num_triangles;
1969 memset(&m, 0, sizeof(m));
1970 m.pointer_vertex = rsurface_vertex3f;
1971 m.tex[0] = R_GetTexture(basetexture);
1972 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1973 m.texmatrix[0] = texture->currenttexmatrix;
1974 if (r_shadow_lightcubemap != r_texture_whitecube)
1976 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
1978 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1979 m.texmatrix[1] = r_shadow_entitytolight;
1981 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1982 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1985 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1987 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
1989 // 2/2 3D combine path (original Radeon)
1990 memset(&m, 0, sizeof(m));
1991 m.pointer_vertex = rsurface_vertex3f;
1992 m.tex[0] = R_GetTexture(normalmaptexture);
1993 m.texcombinergb[0] = GL_REPLACE;
1994 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1995 m.texmatrix[0] = texture->currenttexmatrix;
1996 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1997 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1998 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1999 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);
2001 GL_ColorMask(0,0,0,1);
2002 GL_BlendFunc(GL_ONE, GL_ZERO);
2003 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2004 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2005 GL_LockArrays(0, 0);
2007 c_rt_lighttris += surface->num_triangles;
2009 memset(&m, 0, sizeof(m));
2010 m.pointer_vertex = rsurface_vertex3f;
2011 m.tex[0] = R_GetTexture(basetexture);
2012 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2013 m.texmatrix[0] = texture->currenttexmatrix;
2014 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2016 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2017 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2019 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2020 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2022 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2024 else if (r_textureunits.integer >= 4)
2026 // 4/2 2D combine path (Geforce3, Radeon 8500)
2027 memset(&m, 0, sizeof(m));
2028 m.pointer_vertex = rsurface_vertex3f;
2029 m.tex[0] = R_GetTexture(normalmaptexture);
2030 m.texcombinergb[0] = GL_REPLACE;
2031 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2032 m.texmatrix[0] = texture->currenttexmatrix;
2033 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2034 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2035 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2036 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);
2037 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2039 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2040 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
2042 m.pointer_texcoord[2] = varray_texcoord2f[2];
2043 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2045 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2047 m.pointer_texcoord3f[3] = rsurface_vertex3f;
2048 m.texmatrix[3] = r_shadow_entitytoattenuationz;
2050 m.pointer_texcoord[3] = varray_texcoord2f[3];
2051 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2054 GL_ColorMask(0,0,0,1);
2055 GL_BlendFunc(GL_ONE, GL_ZERO);
2056 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2057 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2058 GL_LockArrays(0, 0);
2060 c_rt_lighttris += surface->num_triangles;
2062 memset(&m, 0, sizeof(m));
2063 m.pointer_vertex = rsurface_vertex3f;
2064 m.tex[0] = R_GetTexture(basetexture);
2065 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2066 m.texmatrix[0] = texture->currenttexmatrix;
2067 if (r_shadow_lightcubemap != r_texture_whitecube)
2069 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2071 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2072 m.texmatrix[1] = r_shadow_entitytolight;
2074 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2075 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2078 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2082 // 2/2/2 2D combine path (any dot3 card)
2083 memset(&m, 0, sizeof(m));
2084 m.pointer_vertex = rsurface_vertex3f;
2085 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2087 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2088 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2090 m.pointer_texcoord[0] = varray_texcoord2f[0];
2091 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2093 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2095 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2096 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2098 m.pointer_texcoord[1] = varray_texcoord2f[1];
2099 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2102 GL_ColorMask(0,0,0,1);
2103 GL_BlendFunc(GL_ONE, GL_ZERO);
2104 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2105 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2106 GL_LockArrays(0, 0);
2108 c_rt_lighttris += surface->num_triangles;
2110 memset(&m, 0, sizeof(m));
2111 m.pointer_vertex = rsurface_vertex3f;
2112 m.tex[0] = R_GetTexture(normalmaptexture);
2113 m.texcombinergb[0] = GL_REPLACE;
2114 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2115 m.texmatrix[0] = texture->currenttexmatrix;
2116 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2117 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2118 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2119 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * 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);
2121 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2122 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2123 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2124 GL_LockArrays(0, 0);
2126 c_rt_lighttris += surface->num_triangles;
2128 memset(&m, 0, sizeof(m));
2129 m.pointer_vertex = rsurface_vertex3f;
2130 m.tex[0] = R_GetTexture(basetexture);
2131 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2132 m.texmatrix[0] = texture->currenttexmatrix;
2133 if (r_shadow_lightcubemap != r_texture_whitecube)
2135 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2137 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2138 m.texmatrix[1] = r_shadow_entitytolight;
2140 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2141 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2144 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2146 // this final code is shared
2148 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2149 VectorScale(lightcolorbase, colorscale, color2);
2150 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2151 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2153 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2154 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2156 c_rt_lighttris += surface->num_triangles;
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_lightcubemap != 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 c_rt_lighttris += surface->num_triangles;
2189 memset(&m, 0, sizeof(m));
2190 m.pointer_vertex = rsurface_vertex3f;
2192 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2193 // square alpha in framebuffer a few times to make it shiny
2194 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2195 // these comments are a test run through this math for intensity 0.5
2196 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2197 // 0.25 * 0.25 = 0.0625 (this is another pass)
2198 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2199 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2201 c_rt_lighttris += surface->num_triangles;
2202 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2204 c_rt_lighttris += surface->num_triangles;
2205 GL_LockArrays(0, 0);
2207 memset(&m, 0, sizeof(m));
2208 m.pointer_vertex = rsurface_vertex3f;
2209 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2211 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2212 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2214 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2215 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2218 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2219 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2220 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2221 GL_LockArrays(0, 0);
2223 c_rt_lighttris += surface->num_triangles;
2225 memset(&m, 0, sizeof(m));
2226 m.pointer_vertex = rsurface_vertex3f;
2227 m.tex[0] = R_GetTexture(glosstexture);
2228 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2229 m.texmatrix[0] = texture->currenttexmatrix;
2230 if (r_shadow_lightcubemap != r_texture_whitecube)
2232 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2234 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2235 m.texmatrix[1] = r_shadow_entitytolight;
2237 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2238 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2241 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2243 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2245 // 2/0/0/2 3D combine blendsquare path
2246 memset(&m, 0, sizeof(m));
2247 m.pointer_vertex = rsurface_vertex3f;
2248 m.tex[0] = R_GetTexture(normalmaptexture);
2249 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2250 m.texmatrix[0] = texture->currenttexmatrix;
2251 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2252 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2253 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2254 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);
2256 GL_ColorMask(0,0,0,1);
2257 // this squares the result
2258 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2259 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2260 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2261 GL_LockArrays(0, 0);
2263 c_rt_lighttris += surface->num_triangles;
2265 memset(&m, 0, sizeof(m));
2266 m.pointer_vertex = rsurface_vertex3f;
2268 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2269 // square alpha in framebuffer a few times to make it shiny
2270 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2271 // these comments are a test run through this math for intensity 0.5
2272 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2273 // 0.25 * 0.25 = 0.0625 (this is another pass)
2274 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2275 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2277 c_rt_lighttris += surface->num_triangles;
2278 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2280 c_rt_lighttris += surface->num_triangles;
2281 GL_LockArrays(0, 0);
2283 memset(&m, 0, sizeof(m));
2284 m.pointer_vertex = rsurface_vertex3f;
2285 m.tex[0] = R_GetTexture(glosstexture);
2286 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2287 m.texmatrix[0] = texture->currenttexmatrix;
2288 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2290 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2291 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2293 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2294 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2296 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2300 // 2/0/0/2/2 2D combine blendsquare path
2301 memset(&m, 0, sizeof(m));
2302 m.pointer_vertex = rsurface_vertex3f;
2303 m.tex[0] = R_GetTexture(normalmaptexture);
2304 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2305 m.texmatrix[0] = texture->currenttexmatrix;
2306 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2307 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2308 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2309 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);
2311 GL_ColorMask(0,0,0,1);
2312 // this squares the result
2313 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2314 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2315 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2316 GL_LockArrays(0, 0);
2318 c_rt_lighttris += surface->num_triangles;
2320 memset(&m, 0, sizeof(m));
2321 m.pointer_vertex = rsurface_vertex3f;
2323 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2324 // square alpha in framebuffer a few times to make it shiny
2325 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2326 // these comments are a test run through this math for intensity 0.5
2327 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2328 // 0.25 * 0.25 = 0.0625 (this is another pass)
2329 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2330 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2332 c_rt_lighttris += surface->num_triangles;
2333 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2335 c_rt_lighttris += surface->num_triangles;
2336 GL_LockArrays(0, 0);
2338 memset(&m, 0, sizeof(m));
2339 m.pointer_vertex = rsurface_vertex3f;
2340 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2342 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2343 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2345 m.pointer_texcoord[0] = varray_texcoord2f[0];
2346 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2348 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2350 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2351 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2353 m.pointer_texcoord[1] = varray_texcoord2f[1];
2354 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2357 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2358 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2359 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2360 GL_LockArrays(0, 0);
2362 c_rt_lighttris += surface->num_triangles;
2364 memset(&m, 0, sizeof(m));
2365 m.pointer_vertex = rsurface_vertex3f;
2366 m.tex[0] = R_GetTexture(glosstexture);
2367 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
2368 m.texmatrix[0] = texture->currenttexmatrix;
2369 if (r_shadow_lightcubemap != r_texture_whitecube)
2371 m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
2373 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2374 m.texmatrix[1] = r_shadow_entitytolight;
2376 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2377 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
2380 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2383 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2384 VectorScale(lightcolorbase, colorscale, color2);
2385 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2386 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2388 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2389 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2391 c_rt_lighttris += surface->num_triangles;
2393 GL_LockArrays(0, 0);
2399 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
2401 int surfacelistindex;
2403 float ambientcolor2[3], diffusecolor2[3];
2405 qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
2406 qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
2407 qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
2408 qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
2409 qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
2410 qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
2411 //qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
2412 // TODO: add direct pants/shirt rendering
2413 if (doambientpants || dodiffusepants)
2414 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
2415 if (doambientshirt || dodiffuseshirt)
2416 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
2417 if (!doambientbase && !dodiffusebase)
2419 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, ambientcolor2);
2420 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, diffusecolor2);
2421 GL_BlendFunc(GL_ONE, GL_ONE);
2422 memset(&m, 0, sizeof(m));
2423 m.tex[0] = R_GetTexture(basetexture);
2424 if (r_textureunits.integer >= 2)
2427 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2429 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2431 m.pointer_texcoord[1] = varray_texcoord2f[1];
2432 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2434 if (r_textureunits.integer >= 3)
2436 // Geforce3/Radeon class but not using dot3
2437 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2439 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2441 m.pointer_texcoord[2] = varray_texcoord2f[2];
2442 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2446 m.pointer_color = varray_color4f;
2448 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2450 const msurface_t *surface = surfacelist[surfacelistindex];
2451 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2452 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2453 if (!rsurface_svector3f)
2455 rsurface_svector3f = varray_svector3f;
2456 rsurface_tvector3f = varray_tvector3f;
2457 rsurface_normal3f = varray_normal3f;
2458 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);
2460 // OpenGL 1.1 path (anything)
2461 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2462 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
2463 if (r_textureunits.integer >= 2)
2467 R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
2469 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2471 if (r_textureunits.integer >= 3)
2473 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2475 R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
2477 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2481 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
2483 if (r_textureunits.integer >= 3)
2484 R_Shadow_VertexShading(surface, diffusecolor2, ambientcolor2, renders);
2485 else if (r_textureunits.integer >= 2)
2486 R_Shadow_VertexShadingWithZAttenuation(surface, diffusecolor2, ambientcolor2, renders);
2488 R_Shadow_VertexShadingWithXYZAttenuation(surface, diffusecolor2, ambientcolor2, renders);
2489 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2490 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2491 GL_LockArrays(0, 0);
2493 c_rt_lighttris += surface->num_triangles;
2498 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
2500 // FIXME: support MATERIALFLAG_NODEPTHTEST
2501 switch (r_shadowstage)
2503 case R_SHADOWSTAGE_VISIBLELIGHTING:
2504 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2506 case R_SHADOWSTAGE_LIGHT_GLSL:
2507 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2509 case R_SHADOWSTAGE_LIGHT_DOT3:
2510 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2512 case R_SHADOWSTAGE_LIGHT_VERTEX:
2513 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
2516 Con_Printf("R_Shadow_RenderLighting: unknown r_shadowstage %i\n", r_shadowstage);
2521 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2525 R_RTLight_Uncompile(rtlight);
2526 memset(rtlight, 0, sizeof(*rtlight));
2528 VectorCopy(light->origin, rtlight->shadoworigin);
2529 VectorCopy(light->color, rtlight->color);
2530 rtlight->radius = light->radius;
2531 //rtlight->cullradius = rtlight->radius;
2532 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2533 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2534 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2535 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2536 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2537 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2538 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2539 rtlight->cubemapname[0] = 0;
2540 if (light->cubemapname[0])
2541 strcpy(rtlight->cubemapname, light->cubemapname);
2542 else if (light->cubemapnum > 0)
2543 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2544 rtlight->shadow = light->shadow;
2545 rtlight->corona = light->corona;
2546 rtlight->style = light->style;
2547 rtlight->isstatic = isstatic;
2548 rtlight->coronasizescale = light->coronasizescale;
2549 rtlight->ambientscale = light->ambientscale;
2550 rtlight->diffusescale = light->diffusescale;
2551 rtlight->specularscale = light->specularscale;
2552 rtlight->flags = light->flags;
2553 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2554 // ConcatScale won't work here because this needs to scale rotate and
2555 // translate, not just rotate
2556 scale = 1.0f / rtlight->radius;
2557 for (k = 0;k < 3;k++)
2558 for (j = 0;j < 4;j++)
2559 rtlight->matrix_worldtolight.m[k][j] *= scale;
2561 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2562 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2563 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2564 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2567 // compiles rtlight geometry
2568 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2569 void R_RTLight_Compile(rtlight_t *rtlight)
2571 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2572 entity_render_t *ent = r_refdef.worldentity;
2573 model_t *model = r_refdef.worldmodel;
2576 // compile the light
2577 rtlight->compiled = true;
2578 rtlight->static_numleafs = 0;
2579 rtlight->static_numleafpvsbytes = 0;
2580 rtlight->static_leaflist = NULL;
2581 rtlight->static_leafpvs = NULL;
2582 rtlight->static_numsurfaces = 0;
2583 rtlight->static_surfacelist = NULL;
2584 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2585 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2586 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2587 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2588 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2589 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2591 if (model && model->GetLightInfo)
2593 // this variable must be set for the CompileShadowVolume code
2594 r_shadow_compilingrtlight = rtlight;
2595 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2596 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);
2597 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2598 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2599 rtlight->static_numleafs = numleafs;
2600 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2601 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2602 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2603 rtlight->static_numsurfaces = numsurfaces;
2604 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2606 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2607 if (numleafpvsbytes)
2608 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2610 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2611 if (model->CompileShadowVolume && rtlight->shadow)
2612 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2613 // now we're done compiling the rtlight
2614 r_shadow_compilingrtlight = NULL;
2618 // use smallest available cullradius - box radius or light radius
2619 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2620 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2624 if (rtlight->static_meshchain_shadow)
2627 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2630 shadowtris += mesh->numtriangles;
2634 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);
2637 void R_RTLight_Uncompile(rtlight_t *rtlight)
2639 if (rtlight->compiled)
2641 if (rtlight->static_meshchain_shadow)
2642 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2643 rtlight->static_meshchain_shadow = NULL;
2644 // these allocations are grouped
2645 if (rtlight->static_leaflist)
2646 Mem_Free(rtlight->static_leaflist);
2647 rtlight->static_numleafs = 0;
2648 rtlight->static_numleafpvsbytes = 0;
2649 rtlight->static_leaflist = NULL;
2650 rtlight->static_leafpvs = NULL;
2651 rtlight->static_numsurfaces = 0;
2652 rtlight->static_surfacelist = NULL;
2653 rtlight->compiled = false;
2657 void R_Shadow_UncompileWorldLights(void)
2660 for (light = r_shadow_worldlightchain;light;light = light->next)
2661 R_RTLight_Uncompile(&light->rtlight);
2664 void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2666 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2667 vec_t relativeshadowradius;
2668 if (ent == r_refdef.worldentity)
2670 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2673 R_Mesh_Matrix(&ent->matrix);
2674 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2676 R_Mesh_VertexPointer(mesh->vertex3f);
2677 GL_LockArrays(0, mesh->numverts);
2678 if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
2680 // decrement stencil if backface is behind depthbuffer
2681 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2682 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2683 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2684 c_rtcached_shadowmeshes++;
2685 c_rtcached_shadowtris += mesh->numtriangles;
2686 // increment stencil if frontface is behind depthbuffer
2687 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2688 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2690 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2691 c_rtcached_shadowmeshes++;
2692 c_rtcached_shadowtris += mesh->numtriangles;
2693 GL_LockArrays(0, 0);
2696 else if (numsurfaces)
2698 R_Mesh_Matrix(&ent->matrix);
2699 ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2704 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
2705 relativeshadowradius = rtlight->radius / ent->scale;
2706 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2707 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2708 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2709 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2710 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2711 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2712 R_Mesh_Matrix(&ent->matrix);
2713 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2717 void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolorbase, int numsurfaces, int *surfacelist)
2719 // set up properties for rendering light onto this entity
2720 r_shadow_entitylightcolor[0] = lightcolorbase[0] * ent->colormod[0] * ent->alpha;
2721 r_shadow_entitylightcolor[1] = lightcolorbase[1] * ent->colormod[1] * ent->alpha;
2722 r_shadow_entitylightcolor[2] = lightcolorbase[2] * ent->colormod[2] * ent->alpha;
2723 Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
2724 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2725 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2726 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
2727 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2728 R_Mesh_Matrix(&ent->matrix);
2729 if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
2731 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
2732 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2733 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
2734 if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
2736 qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
2739 if (ent == r_refdef.worldentity)
2740 ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
2742 ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
2745 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2750 int numleafs, numsurfaces;
2751 int *leaflist, *surfacelist;
2753 int numlightentities;
2754 int numshadowentities;
2755 entity_render_t *lightentities[MAX_EDICTS];
2756 entity_render_t *shadowentities[MAX_EDICTS];
2758 // skip lights that don't light (corona only lights)
2759 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < (1.0f / 32768.0f))
2762 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2763 VectorScale(rtlight->color, f, lightcolor);
2764 if (VectorLength2(lightcolor) < (1.0f / 32768.0f))
2767 if (rtlight->selected)
2769 f = 2 + sin(realtime * M_PI * 4.0);
2770 VectorScale(lightcolor, f, lightcolor);
2774 // loading is done before visibility checks because loading should happen
2775 // all at once at the start of a level, not when it stalls gameplay.
2776 // (especially important to benchmarks)
2778 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2779 R_RTLight_Compile(rtlight);
2781 r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2783 // if the light box is offscreen, skip it
2784 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2787 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2789 // compiled light, world available and can receive realtime lighting
2790 // retrieve leaf information
2791 numleafs = rtlight->static_numleafs;
2792 leaflist = rtlight->static_leaflist;
2793 leafpvs = rtlight->static_leafpvs;
2794 numsurfaces = rtlight->static_numsurfaces;
2795 surfacelist = rtlight->static_surfacelist;
2797 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2799 // dynamic light, world available and can receive realtime lighting
2800 // calculate lit surfaces and leafs
2801 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2802 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);
2803 leaflist = r_shadow_buffer_leaflist;
2804 leafpvs = r_shadow_buffer_leafpvs;
2805 surfacelist = r_shadow_buffer_surfacelist;
2806 // if the reduced leaf bounds are offscreen, skip it
2807 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2819 // check if light is illuminating any visible leafs
2822 for (i = 0;i < numleafs;i++)
2823 if (r_worldleafvisible[leaflist[i]])
2828 // set up a scissor rectangle for this light
2829 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2832 numlightentities = 0;
2834 lightentities[numlightentities++] = r_refdef.worldentity;
2835 numshadowentities = 0;
2837 shadowentities[numshadowentities++] = r_refdef.worldentity;
2838 if (r_drawentities.integer)
2840 for (i = 0;i < r_refdef.numentities;i++)
2842 entity_render_t *ent = r_refdef.entities[i];
2843 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2845 && !(ent->flags & RENDER_TRANSPARENT)
2846 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2848 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2849 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2850 shadowentities[numshadowentities++] = ent;
2851 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2852 lightentities[numlightentities++] = ent;
2857 // return if there's nothing at all to light
2858 if (!numlightentities)
2861 R_Shadow_Stage_ActiveLight(rtlight);
2865 if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2868 R_Shadow_Stage_StencilShadowVolumes();
2869 for (i = 0;i < numshadowentities;i++)
2870 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2873 if (numlightentities && !visible)
2875 R_Shadow_Stage_Lighting(usestencil);
2876 for (i = 0;i < numlightentities;i++)
2877 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2880 if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2882 R_Shadow_Stage_VisibleShadowVolumes();
2883 for (i = 0;i < numshadowentities;i++)
2884 R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
2887 if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
2889 R_Shadow_Stage_VisibleLighting(usestencil);
2890 for (i = 0;i < numlightentities;i++)
2891 R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
2895 void R_ShadowVolumeLighting(qboolean visible)
2900 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2901 R_Shadow_EditLights_Reload_f();
2903 R_Shadow_Stage_Begin();
2905 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2906 if (r_shadow_debuglight.integer >= 0)
2908 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2909 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2910 R_DrawRTLight(&light->rtlight, visible);
2913 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2914 if (light->flags & flag)
2915 R_DrawRTLight(&light->rtlight, visible);
2917 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2918 R_DrawRTLight(&light->rtlight, visible);
2920 R_Shadow_Stage_End();
2923 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2924 typedef struct suffixinfo_s
2927 qboolean flipx, flipy, flipdiagonal;
2930 static suffixinfo_t suffix[3][6] =
2933 {"px", false, false, false},
2934 {"nx", false, false, false},
2935 {"py", false, false, false},
2936 {"ny", false, false, false},
2937 {"pz", false, false, false},
2938 {"nz", false, false, false}
2941 {"posx", false, false, false},
2942 {"negx", false, false, false},
2943 {"posy", false, false, false},
2944 {"negy", false, false, false},
2945 {"posz", false, false, false},
2946 {"negz", false, false, false}
2949 {"rt", true, false, true},
2950 {"lf", false, true, true},
2951 {"ft", true, true, false},
2952 {"bk", false, false, false},
2953 {"up", true, false, true},
2954 {"dn", true, false, true}
2958 static int componentorder[4] = {0, 1, 2, 3};
2960 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2962 int i, j, cubemapsize;
2963 qbyte *cubemappixels, *image_rgba;
2964 rtexture_t *cubemaptexture;
2966 // must start 0 so the first loadimagepixels has no requested width/height
2968 cubemappixels = NULL;
2969 cubemaptexture = NULL;
2970 // keep trying different suffix groups (posx, px, rt) until one loads
2971 for (j = 0;j < 3 && !cubemappixels;j++)
2973 // load the 6 images in the suffix group
2974 for (i = 0;i < 6;i++)
2976 // generate an image name based on the base and and suffix
2977 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2979 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2981 // an image loaded, make sure width and height are equal
2982 if (image_width == image_height)
2984 // if this is the first image to load successfully, allocate the cubemap memory
2985 if (!cubemappixels && image_width >= 1)
2987 cubemapsize = image_width;
2988 // note this clears to black, so unavailable sides are black
2989 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2991 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2993 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);
2996 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2998 Mem_Free(image_rgba);
3002 // if a cubemap loaded, upload it
3005 if (!r_shadow_filters_texturepool)
3006 r_shadow_filters_texturepool = R_AllocTexturePool();
3007 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3008 Mem_Free(cubemappixels);
3012 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3013 for (j = 0;j < 3;j++)
3014 for (i = 0;i < 6;i++)
3015 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3016 Con_Print(" and was unable to find any of them.\n");
3018 return cubemaptexture;
3021 rtexture_t *R_Shadow_Cubemap(const char *basename)
3024 for (i = 0;i < numcubemaps;i++)
3025 if (!strcasecmp(cubemaps[i].basename, basename))
3026 return cubemaps[i].texture;
3027 if (i >= MAX_CUBEMAPS)
3028 return r_texture_whitecube;
3030 strcpy(cubemaps[i].basename, basename);
3031 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3032 if (!cubemaps[i].texture)
3033 cubemaps[i].texture = r_texture_whitecube;
3034 return cubemaps[i].texture;
3037 void R_Shadow_FreeCubemaps(void)
3040 R_FreeTexturePool(&r_shadow_filters_texturepool);
3043 dlight_t *R_Shadow_NewWorldLight(void)
3046 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3047 light->next = r_shadow_worldlightchain;
3048 r_shadow_worldlightchain = light;
3052 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)
3054 VectorCopy(origin, light->origin);
3055 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3056 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3057 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3058 light->color[0] = max(color[0], 0);
3059 light->color[1] = max(color[1], 0);
3060 light->color[2] = max(color[2], 0);
3061 light->radius = max(radius, 0);
3062 light->style = style;
3063 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3065 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3068 light->shadow = shadowenable;
3069 light->corona = corona;
3072 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3073 light->coronasizescale = coronasizescale;
3074 light->ambientscale = ambientscale;
3075 light->diffusescale = diffusescale;
3076 light->specularscale = specularscale;
3077 light->flags = flags;
3078 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3080 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3083 void R_Shadow_FreeWorldLight(dlight_t *light)
3085 dlight_t **lightpointer;
3086 R_RTLight_Uncompile(&light->rtlight);
3087 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3088 if (*lightpointer != light)
3089 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3090 *lightpointer = light->next;
3094 void R_Shadow_ClearWorldLights(void)
3096 while (r_shadow_worldlightchain)
3097 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3098 r_shadow_selectedlight = NULL;
3099 R_Shadow_FreeCubemaps();
3102 void R_Shadow_SelectLight(dlight_t *light)
3104 if (r_shadow_selectedlight)
3105 r_shadow_selectedlight->selected = false;
3106 r_shadow_selectedlight = light;
3107 if (r_shadow_selectedlight)
3108 r_shadow_selectedlight->selected = true;
3111 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3113 float scale = r_editlights_cursorgrid.value * 0.5f;
3114 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
3117 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3120 const dlight_t *light;
3123 if (light->selected)
3124 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3127 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
3130 void R_Shadow_DrawLightSprites(void)
3136 for (i = 0;i < 5;i++)
3138 lighttextures[i] = NULL;
3139 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3140 lighttextures[i] = pic->tex;
3143 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3144 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3145 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3148 void R_Shadow_SelectLightInView(void)
3150 float bestrating, rating, temp[3];
3151 dlight_t *best, *light;
3154 for (light = r_shadow_worldlightchain;light;light = light->next)
3156 VectorSubtract(light->origin, r_vieworigin, temp);
3157 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3160 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3161 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
3163 bestrating = rating;
3168 R_Shadow_SelectLight(best);
3171 void R_Shadow_LoadWorldLights(void)
3173 int n, a, style, shadow, flags;
3174 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3175 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3176 if (r_refdef.worldmodel == NULL)
3178 Con_Print("No map loaded.\n");
3181 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3182 strlcat (name, ".rtlights", sizeof (name));
3183 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3193 for (;COM_Parse(t, true) && strcmp(
3194 if (COM_Parse(t, true))
3196 if (com_token[0] == '!')
3199 origin[0] = atof(com_token+1);
3202 origin[0] = atof(com_token);
3207 while (*s && *s != '\n' && *s != '\r')
3213 // check for modifier flags
3220 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);
3223 flags = LIGHTFLAG_REALTIMEMODE;
3231 coronasizescale = 0.25f;
3233 VectorClear(angles);
3236 if (a < 9 || !strcmp(cubemapname, "\"\""))
3238 // remove quotes on cubemapname
3239 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3241 cubemapname[strlen(cubemapname)-1] = 0;
3242 strcpy(cubemapname, cubemapname + 1);
3246 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);
3249 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3257 Con_Printf("invalid rtlights file \"%s\"\n", name);
3258 Mem_Free(lightsstring);
3262 void R_Shadow_SaveWorldLights(void)
3265 size_t bufchars, bufmaxchars;
3267 char name[MAX_QPATH];
3269 if (!r_shadow_worldlightchain)
3271 if (r_refdef.worldmodel == NULL)
3273 Con_Print("No map loaded.\n");
3276 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3277 strlcat (name, ".rtlights", sizeof (name));
3278 bufchars = bufmaxchars = 0;
3280 for (light = r_shadow_worldlightchain;light;light = light->next)
3282 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3283 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);
3284 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3285 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]);
3287 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);
3288 if (bufchars + strlen(line) > bufmaxchars)
3290 bufmaxchars = bufchars + strlen(line) + 2048;
3292 buf = Mem_Alloc(tempmempool, bufmaxchars);
3296 memcpy(buf, oldbuf, bufchars);
3302 memcpy(buf + bufchars, line, strlen(line));
3303 bufchars += strlen(line);
3307 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3312 void R_Shadow_LoadLightsFile(void)
3315 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3316 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3317 if (r_refdef.worldmodel == NULL)
3319 Con_Print("No map loaded.\n");
3322 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3323 strlcat (name, ".lights", sizeof (name));
3324 lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
3332 while (*s && *s != '\n' && *s != '\r')
3338 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);
3342 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);
3345 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3346 radius = bound(15, radius, 4096);
3347 VectorScale(color, (2.0f / (8388608.0f)), color);
3348 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3356 Con_Printf("invalid lights file \"%s\"\n", name);
3357 Mem_Free(lightsstring);
3361 // tyrlite/hmap2 light types in the delay field
3362 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3364 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3366 int entnum, style, islight, skin, pflags, effects, type, n;
3369 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3370 char key[256], value[1024];
3372 if (r_refdef.worldmodel == NULL)
3374 Con_Print("No map loaded.\n");
3377 // try to load a .ent file first
3378 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3379 strlcat (key, ".ent", sizeof (key));
3380 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true);
3381 // and if that is not found, fall back to the bsp file entity string
3383 data = r_refdef.worldmodel->brush.entities;
3386 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3388 type = LIGHTTYPE_MINUSX;
3389 origin[0] = origin[1] = origin[2] = 0;
3390 originhack[0] = originhack[1] = originhack[2] = 0;
3391 angles[0] = angles[1] = angles[2] = 0;
3392 color[0] = color[1] = color[2] = 1;
3393 light[0] = light[1] = light[2] = 1;light[3] = 300;
3394 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3404 if (!COM_ParseToken(&data, false))
3406 if (com_token[0] == '}')
3407 break; // end of entity
3408 if (com_token[0] == '_')
3409 strcpy(key, com_token + 1);
3411 strcpy(key, com_token);
3412 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3413 key[strlen(key)-1] = 0;
3414 if (!COM_ParseToken(&data, false))
3416 strcpy(value, com_token);
3418 // now that we have the key pair worked out...
3419 if (!strcmp("light", key))
3421 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3425 light[0] = vec[0] * (1.0f / 256.0f);
3426 light[1] = vec[0] * (1.0f / 256.0f);
3427 light[2] = vec[0] * (1.0f / 256.0f);
3433 light[0] = vec[0] * (1.0f / 255.0f);
3434 light[1] = vec[1] * (1.0f / 255.0f);
3435 light[2] = vec[2] * (1.0f / 255.0f);
3439 else if (!strcmp("delay", key))
3441 else if (!strcmp("origin", key))
3442 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3443 else if (!strcmp("angle", key))
3444 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3445 else if (!strcmp("angles", key))
3446 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3447 else if (!strcmp("color", key))
3448 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3449 else if (!strcmp("wait", key))
3450 fadescale = atof(value);
3451 else if (!strcmp("classname", key))
3453 if (!strncmp(value, "light", 5))
3456 if (!strcmp(value, "light_fluoro"))
3461 overridecolor[0] = 1;
3462 overridecolor[1] = 1;
3463 overridecolor[2] = 1;
3465 if (!strcmp(value, "light_fluorospark"))
3470 overridecolor[0] = 1;
3471 overridecolor[1] = 1;
3472 overridecolor[2] = 1;
3474 if (!strcmp(value, "light_globe"))
3479 overridecolor[0] = 1;
3480 overridecolor[1] = 0.8;
3481 overridecolor[2] = 0.4;
3483 if (!strcmp(value, "light_flame_large_yellow"))
3488 overridecolor[0] = 1;
3489 overridecolor[1] = 0.5;
3490 overridecolor[2] = 0.1;
3492 if (!strcmp(value, "light_flame_small_yellow"))
3497 overridecolor[0] = 1;
3498 overridecolor[1] = 0.5;
3499 overridecolor[2] = 0.1;
3501 if (!strcmp(value, "light_torch_small_white"))
3506 overridecolor[0] = 1;
3507 overridecolor[1] = 0.5;
3508 overridecolor[2] = 0.1;
3510 if (!strcmp(value, "light_torch_small_walltorch"))
3515 overridecolor[0] = 1;
3516 overridecolor[1] = 0.5;
3517 overridecolor[2] = 0.1;
3521 else if (!strcmp("style", key))
3522 style = atoi(value);
3523 else if (!strcmp("skin", key))
3524 skin = (int)atof(value);
3525 else if (!strcmp("pflags", key))
3526 pflags = (int)atof(value);
3527 else if (!strcmp("effects", key))
3528 effects = (int)atof(value);
3529 else if (r_refdef.worldmodel->type == mod_brushq3)
3531 if (!strcmp("scale", key))
3532 lightscale = atof(value);
3533 if (!strcmp("fade", key))
3534 fadescale = atof(value);
3539 if (lightscale <= 0)
3543 if (color[0] == color[1] && color[0] == color[2])
3545 color[0] *= overridecolor[0];
3546 color[1] *= overridecolor[1];
3547 color[2] *= overridecolor[2];
3549 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3550 color[0] = color[0] * light[0];
3551 color[1] = color[1] * light[1];
3552 color[2] = color[2] * light[2];
3555 case LIGHTTYPE_MINUSX:
3557 case LIGHTTYPE_RECIPX:
3559 VectorScale(color, (1.0f / 16.0f), color);
3561 case LIGHTTYPE_RECIPXX:
3563 VectorScale(color, (1.0f / 16.0f), color);
3566 case LIGHTTYPE_NONE:
3570 case LIGHTTYPE_MINUSXX:
3573 VectorAdd(origin, originhack, origin);
3575 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);
3578 Mem_Free(entfiledata);
3582 void R_Shadow_SetCursorLocationForView(void)
3585 vec3_t dest, endpos;
3587 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3588 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3589 if (trace.fraction < 1)
3591 dist = trace.fraction * r_editlights_cursordistance.value;
3592 push = r_editlights_cursorpushback.value;
3596 VectorMA(trace.endpos, push, r_viewforward, endpos);
3597 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3601 VectorClear( endpos );
3603 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3604 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3605 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3608 void R_Shadow_UpdateWorldLightSelection(void)
3610 if (r_editlights.integer)
3612 R_Shadow_SetCursorLocationForView();
3613 R_Shadow_SelectLightInView();
3614 R_Shadow_DrawLightSprites();
3617 R_Shadow_SelectLight(NULL);
3620 void R_Shadow_EditLights_Clear_f(void)
3622 R_Shadow_ClearWorldLights();
3625 void R_Shadow_EditLights_Reload_f(void)
3627 if (!r_refdef.worldmodel)
3629 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3630 R_Shadow_ClearWorldLights();
3631 R_Shadow_LoadWorldLights();
3632 if (r_shadow_worldlightchain == NULL)
3634 R_Shadow_LoadLightsFile();
3635 if (r_shadow_worldlightchain == NULL)
3636 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3640 void R_Shadow_EditLights_Save_f(void)
3642 if (!r_refdef.worldmodel)
3644 R_Shadow_SaveWorldLights();
3647 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3649 R_Shadow_ClearWorldLights();
3650 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3653 void R_Shadow_EditLights_ImportLightsFile_f(void)
3655 R_Shadow_ClearWorldLights();
3656 R_Shadow_LoadLightsFile();
3659 void R_Shadow_EditLights_Spawn_f(void)
3662 if (!r_editlights.integer)
3664 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3667 if (Cmd_Argc() != 1)
3669 Con_Print("r_editlights_spawn does not take parameters\n");
3672 color[0] = color[1] = color[2] = 1;
3673 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3676 void R_Shadow_EditLights_Edit_f(void)
3678 vec3_t origin, angles, color;
3679 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3680 int style, shadows, flags, normalmode, realtimemode;
3681 char cubemapname[1024];
3682 if (!r_editlights.integer)
3684 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3687 if (!r_shadow_selectedlight)
3689 Con_Print("No selected light.\n");
3692 VectorCopy(r_shadow_selectedlight->origin, origin);
3693 VectorCopy(r_shadow_selectedlight->angles, angles);
3694 VectorCopy(r_shadow_selectedlight->color, color);
3695 radius = r_shadow_selectedlight->radius;
3696 style = r_shadow_selectedlight->style;
3697 if (r_shadow_selectedlight->cubemapname)
3698 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3701 shadows = r_shadow_selectedlight->shadow;
3702 corona = r_shadow_selectedlight->corona;
3703 coronasizescale = r_shadow_selectedlight->coronasizescale;
3704 ambientscale = r_shadow_selectedlight->ambientscale;
3705 diffusescale = r_shadow_selectedlight->diffusescale;
3706 specularscale = r_shadow_selectedlight->specularscale;
3707 flags = r_shadow_selectedlight->flags;
3708 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3709 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3710 if (!strcmp(Cmd_Argv(1), "origin"))
3712 if (Cmd_Argc() != 5)
3714 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3717 origin[0] = atof(Cmd_Argv(2));
3718 origin[1] = atof(Cmd_Argv(3));
3719 origin[2] = atof(Cmd_Argv(4));
3721 else if (!strcmp(Cmd_Argv(1), "originx"))
3723 if (Cmd_Argc() != 3)
3725 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3728 origin[0] = atof(Cmd_Argv(2));
3730 else if (!strcmp(Cmd_Argv(1), "originy"))
3732 if (Cmd_Argc() != 3)
3734 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3737 origin[1] = atof(Cmd_Argv(2));
3739 else if (!strcmp(Cmd_Argv(1), "originz"))
3741 if (Cmd_Argc() != 3)
3743 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3746 origin[2] = atof(Cmd_Argv(2));
3748 else if (!strcmp(Cmd_Argv(1), "move"))
3750 if (Cmd_Argc() != 5)
3752 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3755 origin[0] += atof(Cmd_Argv(2));
3756 origin[1] += atof(Cmd_Argv(3));
3757 origin[2] += atof(Cmd_Argv(4));
3759 else if (!strcmp(Cmd_Argv(1), "movex"))
3761 if (Cmd_Argc() != 3)
3763 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3766 origin[0] += atof(Cmd_Argv(2));
3768 else if (!strcmp(Cmd_Argv(1), "movey"))
3770 if (Cmd_Argc() != 3)
3772 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3775 origin[1] += atof(Cmd_Argv(2));
3777 else if (!strcmp(Cmd_Argv(1), "movez"))
3779 if (Cmd_Argc() != 3)
3781 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3784 origin[2] += atof(Cmd_Argv(2));
3786 else if (!strcmp(Cmd_Argv(1), "angles"))
3788 if (Cmd_Argc() != 5)
3790 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3793 angles[0] = atof(Cmd_Argv(2));
3794 angles[1] = atof(Cmd_Argv(3));
3795 angles[2] = atof(Cmd_Argv(4));
3797 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3799 if (Cmd_Argc() != 3)
3801 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3804 angles[0] = atof(Cmd_Argv(2));
3806 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3808 if (Cmd_Argc() != 3)
3810 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3813 angles[1] = atof(Cmd_Argv(2));
3815 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3817 if (Cmd_Argc() != 3)
3819 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3822 angles[2] = atof(Cmd_Argv(2));
3824 else if (!strcmp(Cmd_Argv(1), "color"))
3826 if (Cmd_Argc() != 5)
3828 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3831 color[0] = atof(Cmd_Argv(2));
3832 color[1] = atof(Cmd_Argv(3));
3833 color[2] = atof(Cmd_Argv(4));
3835 else if (!strcmp(Cmd_Argv(1), "radius"))
3837 if (Cmd_Argc() != 3)
3839 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3842 radius = atof(Cmd_Argv(2));
3844 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3846 if (Cmd_Argc() == 3)
3848 double scale = atof(Cmd_Argv(2));
3855 if (Cmd_Argc() != 5)
3857 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3860 color[0] *= atof(Cmd_Argv(2));
3861 color[1] *= atof(Cmd_Argv(3));
3862 color[2] *= atof(Cmd_Argv(4));
3865 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3867 if (Cmd_Argc() != 3)
3869 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3872 radius *= atof(Cmd_Argv(2));
3874 else if (!strcmp(Cmd_Argv(1), "style"))
3876 if (Cmd_Argc() != 3)
3878 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3881 style = atoi(Cmd_Argv(2));
3883 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3887 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3890 if (Cmd_Argc() == 3)
3891 strcpy(cubemapname, Cmd_Argv(2));
3895 else if (!strcmp(Cmd_Argv(1), "shadows"))
3897 if (Cmd_Argc() != 3)
3899 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3902 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3904 else if (!strcmp(Cmd_Argv(1), "corona"))
3906 if (Cmd_Argc() != 3)
3908 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3911 corona = atof(Cmd_Argv(2));
3913 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3915 if (Cmd_Argc() != 3)
3917 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3920 coronasizescale = atof(Cmd_Argv(2));
3922 else if (!strcmp(Cmd_Argv(1), "ambient"))
3924 if (Cmd_Argc() != 3)
3926 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3929 ambientscale = atof(Cmd_Argv(2));
3931 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3933 if (Cmd_Argc() != 3)
3935 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3938 diffusescale = atof(Cmd_Argv(2));
3940 else if (!strcmp(Cmd_Argv(1), "specular"))
3942 if (Cmd_Argc() != 3)
3944 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3947 specularscale = atof(Cmd_Argv(2));
3949 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3951 if (Cmd_Argc() != 3)
3953 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3956 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3958 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3960 if (Cmd_Argc() != 3)
3962 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3965 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3969 Con_Print("usage: r_editlights_edit [property] [value]\n");
3970 Con_Print("Selected light's properties:\n");
3971 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3972 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3973 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3974 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3975 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3976 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3977 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3978 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3979 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3980 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3981 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3982 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3983 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3984 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3987 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3988 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3991 void R_Shadow_EditLights_EditAll_f(void)
3995 if (!r_editlights.integer)
3997 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4001 for (light = r_shadow_worldlightchain;light;light = light->next)
4003 R_Shadow_SelectLight(light);
4004 R_Shadow_EditLights_Edit_f();
4008 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4010 int lightnumber, lightcount;
4014 if (!r_editlights.integer)
4020 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4021 if (light == r_shadow_selectedlight)
4022 lightnumber = lightcount;
4023 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;
4024 if (r_shadow_selectedlight == NULL)
4026 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4027 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;
4028 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;
4029 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;
4030 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4031 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4032 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4033 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;
4034 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4035 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4036 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4037 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4038 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4039 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;
4040 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;
4043 void R_Shadow_EditLights_ToggleShadow_f(void)
4045 if (!r_editlights.integer)
4047 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4050 if (!r_shadow_selectedlight)
4052 Con_Print("No selected light.\n");
4055 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);
4058 void R_Shadow_EditLights_ToggleCorona_f(void)
4060 if (!r_editlights.integer)
4062 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4065 if (!r_shadow_selectedlight)
4067 Con_Print("No selected light.\n");
4070 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);
4073 void R_Shadow_EditLights_Remove_f(void)
4075 if (!r_editlights.integer)
4077 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4080 if (!r_shadow_selectedlight)
4082 Con_Print("No selected light.\n");
4085 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4086 r_shadow_selectedlight = NULL;
4089 void R_Shadow_EditLights_Help_f(void)
4092 "Documentation on r_editlights system:\n"
4094 "r_editlights : enable/disable editing mode\n"
4095 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4096 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4097 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4098 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4099 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4101 "r_editlights_help : this help\n"
4102 "r_editlights_clear : remove all lights\n"
4103 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4104 "r_editlights_save : save to .rtlights file\n"
4105 "r_editlights_spawn : create a light with default settings\n"
4106 "r_editlights_edit command : edit selected light - more documentation below\n"
4107 "r_editlights_remove : remove selected light\n"
4108 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4109 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4110 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4112 "origin x y z : set light location\n"
4113 "originx x: set x component of light location\n"
4114 "originy y: set y component of light location\n"
4115 "originz z: set z component of light location\n"
4116 "move x y z : adjust light location\n"
4117 "movex x: adjust x component of light location\n"
4118 "movey y: adjust y component of light location\n"
4119 "movez z: adjust z component of light location\n"
4120 "angles x y z : set light angles\n"
4121 "anglesx x: set x component of light angles\n"
4122 "anglesy y: set y component of light angles\n"
4123 "anglesz z: set z component of light angles\n"
4124 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4125 "radius radius : set radius (size) of light\n"
4126 "colorscale grey : multiply color of light (1 does nothing)\n"
4127 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4128 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4129 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4130 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4131 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4132 "shadows 1/0 : turn on/off shadows\n"
4133 "corona n : set corona intensity\n"
4134 "coronasize n : set corona size (0-1)\n"
4135 "ambient n : set ambient intensity (0-1)\n"
4136 "diffuse n : set diffuse intensity (0-1)\n"
4137 "specular n : set specular intensity (0-1)\n"
4138 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4139 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4140 "<nothing> : print light properties to console\n"
4144 void R_Shadow_EditLights_CopyInfo_f(void)
4146 if (!r_editlights.integer)
4148 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4151 if (!r_shadow_selectedlight)
4153 Con_Print("No selected light.\n");
4156 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4157 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4158 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4159 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4160 if (r_shadow_selectedlight->cubemapname)
4161 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4163 r_shadow_bufferlight.cubemapname[0] = 0;
4164 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4165 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4166 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4167 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4168 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4169 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4170 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4173 void R_Shadow_EditLights_PasteInfo_f(void)
4175 if (!r_editlights.integer)
4177 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4180 if (!r_shadow_selectedlight)
4182 Con_Print("No selected light.\n");
4185 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);
4188 void R_Shadow_EditLights_Init(void)
4190 Cvar_RegisterVariable(&r_editlights);
4191 Cvar_RegisterVariable(&r_editlights_cursordistance);
4192 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4193 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4194 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4195 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4196 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4197 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4198 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4199 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4200 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4201 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4202 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4203 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4204 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4205 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4206 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4207 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4208 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4209 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);