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 rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numleafpvsbytes;
146 qbyte *r_shadow_buffer_leafpvs;
147 int *r_shadow_buffer_leaflist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankwhitecubetexture;
159 // lights are reloaded when this changes
160 char r_shadow_mapname[MAX_QPATH];
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
165 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
166 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
167 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
168 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
169 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
170 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
171 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
172 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
173 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
174 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
175 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
176 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
177 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
178 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
179 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
180 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
181 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
182 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
183 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
184 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
185 cvar_t r_shadow_realtime_world_compilelight = {0, "r_shadow_realtime_world_compilelight", "1"};
186 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
187 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
188 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
189 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
190 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
191 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
192 cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
193 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
194 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
195 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "1"};
196 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "0.04"};
197 cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "-0.04"};
198 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
199 cvar_t r_editlights = {0, "r_editlights", "0"};
200 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
201 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
202 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
203 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
204 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
205 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
206 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
208 float r_shadow_attenpower, r_shadow_attenscale;
210 rtlight_t *r_shadow_compilingrtlight;
211 dlight_t *r_shadow_worldlightchain;
212 dlight_t *r_shadow_selectedlight;
213 dlight_t r_shadow_bufferlight;
214 vec3_t r_editlights_cursorlocation;
216 rtexture_t *lighttextures[5];
218 extern int con_vislines;
220 typedef struct cubemapinfo_s
227 #define MAX_CUBEMAPS 256
228 static int numcubemaps;
229 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
231 #define SHADERPERMUTATION_SPECULAR (1<<0)
232 #define SHADERPERMUTATION_FOG (1<<1)
233 #define SHADERPERMUTATION_CUBEFILTER (1<<2)
234 #define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
235 #define SHADERPERMUTATION_COUNT (1<<4)
237 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
239 void R_Shadow_UncompileWorldLights(void);
240 void R_Shadow_ClearWorldLights(void);
241 void R_Shadow_SaveWorldLights(void);
242 void R_Shadow_LoadWorldLights(void);
243 void R_Shadow_LoadLightsFile(void);
244 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
245 void R_Shadow_EditLights_Reload_f(void);
246 void R_Shadow_ValidateCvars(void);
247 static void R_Shadow_MakeTextures(void);
248 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
250 const char *builtinshader_light_vert =
251 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
252 "// written by Forest 'LordHavoc' Hale\n"
254 "uniform vec3 LightPosition;\n"
256 "varying vec2 TexCoord;\n"
257 "varying vec3 CubeVector;\n"
258 "varying vec3 LightVector;\n"
260 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
261 "uniform vec3 EyePosition;\n"
262 "varying vec3 EyeVector;\n"
265 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
269 " // copy the surface texcoord\n"
270 " TexCoord = gl_MultiTexCoord0.st;\n"
272 " // transform vertex position into light attenuation/cubemap space\n"
273 " // (-1 to +1 across the light box)\n"
274 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
276 " // transform unnormalized light direction into tangent space\n"
277 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
278 " // normalize it per pixel)\n"
279 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
280 " LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
281 " LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
282 " LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
284 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
285 " // transform unnormalized eye direction into tangent space\n"
286 " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
287 " EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
288 " EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
289 " EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
292 " // transform vertex to camera space, using ftransform to match non-VS\n"
294 " gl_Position = ftransform();\n"
298 const char *builtinshader_light_frag =
299 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
300 "// written by Forest 'LordHavoc' Hale\n"
302 "uniform vec3 LightColor;\n"
304 "#ifdef USEOFFSETMAPPING\n"
305 "uniform float OffsetMapping_Scale;\n"
306 "uniform float OffsetMapping_Bias;\n"
308 "#ifdef USESPECULAR\n"
309 "uniform float SpecularPower;\n"
312 "uniform float FogRangeRecip;\n"
314 "uniform float AmbientScale;\n"
315 "uniform float DiffuseScale;\n"
316 "#ifdef USESPECULAR\n"
317 "uniform float SpecularScale;\n"
320 "uniform sampler2D Texture_Normal;\n"
321 "uniform sampler2D Texture_Color;\n"
322 "#ifdef USESPECULAR\n"
323 "uniform sampler2D Texture_Gloss;\n"
325 "#ifdef USECUBEFILTER\n"
326 "uniform samplerCube Texture_Cube;\n"
329 "uniform sampler2D Texture_FogMask;\n"
332 "varying vec2 TexCoord;\n"
333 "varying vec3 CubeVector;\n"
334 "varying vec3 LightVector;\n"
335 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
336 "varying vec3 EyeVector;\n"
343 " // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
344 " // center and sharp falloff at the edge, this is about the most efficient\n"
345 " // we can get away with as far as providing illumination.\n"
347 " // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
348 " // provide significant illumination, large = slow = pain.\n"
349 " float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
353 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
356 "#ifdef USEOFFSETMAPPING\n"
357 " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
358 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
359 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
360 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
361 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
362 "#define TexCoord TexCoordOffset\n"
365 " // get the texels - with a blendmap we'd need to blend multiple here\n"
366 " vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
367 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
368 "#ifdef USESPECULAR\n"
369 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
372 " // calculate shading\n"
373 " vec3 diffusenormal = normalize(LightVector);\n"
374 " vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
375 "#ifdef USESPECULAR\n"
376 " color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
379 "#ifdef USECUBEFILTER\n"
380 " // apply light cubemap filter\n"
381 " color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
384 " // calculate fragment color\n"
385 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
389 void r_shadow_start(void)
392 // allocate vertex processing arrays
394 r_shadow_normalcubetexture = NULL;
395 r_shadow_attenuation2dtexture = NULL;
396 r_shadow_attenuation3dtexture = NULL;
397 r_shadow_blankwhitecubetexture = NULL;
398 r_shadow_texturepool = NULL;
399 r_shadow_filters_texturepool = NULL;
400 R_Shadow_ValidateCvars();
401 R_Shadow_MakeTextures();
402 maxshadowelements = 0;
403 shadowelements = NULL;
411 shadowmarklist = NULL;
413 r_shadow_buffer_numleafpvsbytes = 0;
414 r_shadow_buffer_leafpvs = NULL;
415 r_shadow_buffer_leaflist = NULL;
416 r_shadow_buffer_numsurfacepvsbytes = 0;
417 r_shadow_buffer_surfacepvs = NULL;
418 r_shadow_buffer_surfacelist = NULL;
419 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
420 r_shadow_program_light[i] = 0;
421 if (gl_support_fragment_shader)
423 char *vertstring, *fragstring;
424 int vertstrings_count;
425 int fragstrings_count;
426 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
427 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
428 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
429 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
430 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
432 vertstrings_count = 0;
433 fragstrings_count = 0;
434 if (i & SHADERPERMUTATION_SPECULAR)
436 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
437 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
439 if (i & SHADERPERMUTATION_FOG)
441 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
442 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
444 if (i & SHADERPERMUTATION_CUBEFILTER)
446 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
447 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
449 if (i & SHADERPERMUTATION_OFFSETMAPPING)
451 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
452 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
454 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
455 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
456 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
457 if (!r_shadow_program_light[i])
459 Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
462 qglUseProgramObjectARB(r_shadow_program_light[i]);
463 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
464 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
465 if (i & SHADERPERMUTATION_SPECULAR)
467 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
469 if (i & SHADERPERMUTATION_CUBEFILTER)
471 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
473 if (i & SHADERPERMUTATION_FOG)
475 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
478 qglUseProgramObjectARB(0);
480 Mem_Free(fragstring);
482 Mem_Free(vertstring);
486 void r_shadow_shutdown(void)
489 R_Shadow_UncompileWorldLights();
490 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
492 if (r_shadow_program_light[i])
494 GL_Backend_FreeProgram(r_shadow_program_light[i]);
495 r_shadow_program_light[i] = 0;
499 r_shadow_normalcubetexture = NULL;
500 r_shadow_attenuation2dtexture = NULL;
501 r_shadow_attenuation3dtexture = NULL;
502 r_shadow_blankwhitecubetexture = NULL;
503 R_FreeTexturePool(&r_shadow_texturepool);
504 R_FreeTexturePool(&r_shadow_filters_texturepool);
505 maxshadowelements = 0;
507 Mem_Free(shadowelements);
508 shadowelements = NULL;
511 Mem_Free(vertexupdate);
514 Mem_Free(vertexremap);
520 Mem_Free(shadowmark);
523 Mem_Free(shadowmarklist);
524 shadowmarklist = NULL;
526 r_shadow_buffer_numleafpvsbytes = 0;
527 if (r_shadow_buffer_leafpvs)
528 Mem_Free(r_shadow_buffer_leafpvs);
529 r_shadow_buffer_leafpvs = NULL;
530 if (r_shadow_buffer_leaflist)
531 Mem_Free(r_shadow_buffer_leaflist);
532 r_shadow_buffer_leaflist = NULL;
533 r_shadow_buffer_numsurfacepvsbytes = 0;
534 if (r_shadow_buffer_surfacepvs)
535 Mem_Free(r_shadow_buffer_surfacepvs);
536 r_shadow_buffer_surfacepvs = NULL;
537 if (r_shadow_buffer_surfacelist)
538 Mem_Free(r_shadow_buffer_surfacelist);
539 r_shadow_buffer_surfacelist = NULL;
542 void r_shadow_newmap(void)
546 void R_Shadow_Help_f(void)
549 "Documentation on r_shadow system:\n"
551 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
552 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
553 "r_shadow_debuglight : render only this light number (-1 = all)\n"
554 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
555 "r_shadow_gloss2intensity : brightness of forced gloss\n"
556 "r_shadow_glossintensity : brightness of textured gloss\n"
557 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
558 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
559 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
560 "r_shadow_portallight : use portal visibility for static light precomputation\n"
561 "r_shadow_projectdistance : shadow volume projection distance\n"
562 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
563 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
564 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
565 "r_shadow_realtime_world : use high quality world lighting mode\n"
566 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
567 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
568 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
569 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
570 "r_shadow_realtime_world_compilelight : compile lighting geometry\n"
571 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
572 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
573 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
574 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
575 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
576 "r_shadow_scissor : use scissor optimization\n"
577 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
578 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
579 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
580 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
581 "r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
582 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
584 "r_shadow_help : this help\n"
588 void R_Shadow_Init(void)
590 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
591 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
592 Cvar_RegisterVariable(&r_shadow_cull);
593 Cvar_RegisterVariable(&r_shadow_debuglight);
594 Cvar_RegisterVariable(&r_shadow_gloss);
595 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
596 Cvar_RegisterVariable(&r_shadow_glossintensity);
597 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
598 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
599 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
600 Cvar_RegisterVariable(&r_shadow_portallight);
601 Cvar_RegisterVariable(&r_shadow_projectdistance);
602 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
603 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
604 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
605 Cvar_RegisterVariable(&r_shadow_realtime_world);
606 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
607 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
608 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
609 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
610 Cvar_RegisterVariable(&r_shadow_realtime_world_compilelight);
611 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
612 Cvar_RegisterVariable(&r_shadow_scissor);
613 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
614 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
615 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
616 Cvar_RegisterVariable(&r_shadow_texture3d);
617 Cvar_RegisterVariable(&r_shadow_visiblelighting);
618 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
619 Cvar_RegisterVariable(&r_shadow_glsl);
620 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
621 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
622 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
623 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
624 if (gamemode == GAME_TENEBRAE)
626 Cvar_SetValue("r_shadow_gloss", 2);
627 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
629 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
630 R_Shadow_EditLights_Init();
631 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
632 r_shadow_worldlightchain = NULL;
633 maxshadowelements = 0;
634 shadowelements = NULL;
642 shadowmarklist = NULL;
644 r_shadow_buffer_numleafpvsbytes = 0;
645 r_shadow_buffer_leafpvs = NULL;
646 r_shadow_buffer_leaflist = NULL;
647 r_shadow_buffer_numsurfacepvsbytes = 0;
648 r_shadow_buffer_surfacepvs = NULL;
649 r_shadow_buffer_surfacelist = NULL;
650 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
653 static matrix4x4_t matrix_attenuationxyz =
656 {0.5, 0.0, 0.0, 0.5},
657 {0.0, 0.5, 0.0, 0.5},
658 {0.0, 0.0, 0.5, 0.5},
663 static matrix4x4_t matrix_attenuationz =
666 {0.0, 0.0, 0.5, 0.5},
667 {0.0, 0.0, 0.0, 0.5},
668 {0.0, 0.0, 0.0, 0.5},
673 int *R_Shadow_ResizeShadowElements(int numtris)
675 // make sure shadowelements is big enough for this volume
676 if (maxshadowelements < numtris * 24)
678 maxshadowelements = numtris * 24;
680 Mem_Free(shadowelements);
681 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
683 return shadowelements;
686 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
688 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
689 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
690 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
692 if (r_shadow_buffer_leafpvs)
693 Mem_Free(r_shadow_buffer_leafpvs);
694 if (r_shadow_buffer_leaflist)
695 Mem_Free(r_shadow_buffer_leaflist);
696 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
697 r_shadow_buffer_leafpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
698 r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
700 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
702 if (r_shadow_buffer_surfacepvs)
703 Mem_Free(r_shadow_buffer_surfacepvs);
704 if (r_shadow_buffer_surfacelist)
705 Mem_Free(r_shadow_buffer_surfacelist);
706 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
707 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
708 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
712 void R_Shadow_PrepareShadowMark(int numtris)
714 // make sure shadowmark is big enough for this volume
715 if (maxshadowmark < numtris)
717 maxshadowmark = numtris;
719 Mem_Free(shadowmark);
721 Mem_Free(shadowmarklist);
722 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
723 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
727 // if shadowmarkcount wrapped we clear the array and adjust accordingly
728 if (shadowmarkcount == 0)
731 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
736 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)
739 int outtriangles = 0, outvertices = 0;
743 if (maxvertexupdate < innumvertices)
745 maxvertexupdate = innumvertices;
747 Mem_Free(vertexupdate);
749 Mem_Free(vertexremap);
750 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
751 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
755 if (vertexupdatenum == 0)
758 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
759 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
762 for (i = 0;i < numshadowmarktris;i++)
763 shadowmark[shadowmarktris[i]] = shadowmarkcount;
765 for (i = 0;i < numshadowmarktris;i++)
767 element = inelement3i + shadowmarktris[i] * 3;
768 // make sure the vertices are created
769 for (j = 0;j < 3;j++)
771 if (vertexupdate[element[j]] != vertexupdatenum)
773 float ratio, direction[3];
774 vertexupdate[element[j]] = vertexupdatenum;
775 vertexremap[element[j]] = outvertices;
776 vertex = invertex3f + element[j] * 3;
777 // project one copy of the vertex to the sphere radius of the light
778 // (FIXME: would projecting it to the light box be better?)
779 VectorSubtract(vertex, projectorigin, direction);
780 ratio = projectdistance / VectorLength(direction);
781 VectorCopy(vertex, outvertex3f);
782 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
789 for (i = 0;i < numshadowmarktris;i++)
791 int remappedelement[3];
793 const int *neighbortriangle;
795 markindex = shadowmarktris[i] * 3;
796 element = inelement3i + markindex;
797 neighbortriangle = inneighbor3i + markindex;
798 // output the front and back triangles
799 outelement3i[0] = vertexremap[element[0]];
800 outelement3i[1] = vertexremap[element[1]];
801 outelement3i[2] = vertexremap[element[2]];
802 outelement3i[3] = vertexremap[element[2]] + 1;
803 outelement3i[4] = vertexremap[element[1]] + 1;
804 outelement3i[5] = vertexremap[element[0]] + 1;
808 // output the sides (facing outward from this triangle)
809 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
811 remappedelement[0] = vertexremap[element[0]];
812 remappedelement[1] = vertexremap[element[1]];
813 outelement3i[0] = remappedelement[1];
814 outelement3i[1] = remappedelement[0];
815 outelement3i[2] = remappedelement[0] + 1;
816 outelement3i[3] = remappedelement[1];
817 outelement3i[4] = remappedelement[0] + 1;
818 outelement3i[5] = remappedelement[1] + 1;
823 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
825 remappedelement[1] = vertexremap[element[1]];
826 remappedelement[2] = vertexremap[element[2]];
827 outelement3i[0] = remappedelement[2];
828 outelement3i[1] = remappedelement[1];
829 outelement3i[2] = remappedelement[1] + 1;
830 outelement3i[3] = remappedelement[2];
831 outelement3i[4] = remappedelement[1] + 1;
832 outelement3i[5] = remappedelement[2] + 1;
837 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
839 remappedelement[0] = vertexremap[element[0]];
840 remappedelement[2] = vertexremap[element[2]];
841 outelement3i[0] = remappedelement[0];
842 outelement3i[1] = remappedelement[2];
843 outelement3i[2] = remappedelement[2] + 1;
844 outelement3i[3] = remappedelement[0];
845 outelement3i[4] = remappedelement[2] + 1;
846 outelement3i[5] = remappedelement[0] + 1;
853 *outnumvertices = outvertices;
857 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)
860 if (projectdistance < 0.1)
862 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
865 if (!numverts || !nummarktris)
867 // make sure shadowelements is big enough for this volume
868 if (maxshadowelements < nummarktris * 24)
869 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
870 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
871 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
874 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)
879 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
881 tend = firsttriangle + numtris;
882 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
883 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
884 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
886 // surface box entirely inside light box, no box cull
887 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
888 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
889 shadowmarklist[numshadowmark++] = t;
893 // surface box not entirely inside light box, cull each triangle
894 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
896 v[0] = invertex3f + e[0] * 3;
897 v[1] = invertex3f + e[1] * 3;
898 v[2] = invertex3f + e[2] * 3;
899 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
900 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
901 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
902 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
903 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
904 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
905 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
906 shadowmarklist[numshadowmark++] = t;
911 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
914 if (r_shadow_compilingrtlight)
916 // if we're compiling an rtlight, capture the mesh
917 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
920 memset(&m, 0, sizeof(m));
921 m.pointer_vertex = vertex3f;
923 GL_LockArrays(0, numvertices);
924 if (r_shadowstage == SHADOWSTAGE_STENCIL)
926 // increment stencil if backface is behind depthbuffer
927 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
928 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
929 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
931 c_rt_shadowtris += numtriangles;
932 // decrement stencil if frontface is behind depthbuffer
933 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
934 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
936 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
938 c_rt_shadowtris += numtriangles;
942 static void R_Shadow_MakeTextures(void)
944 int x, y, z, d, side;
945 float v[3], s, t, intensity;
947 R_FreeTexturePool(&r_shadow_texturepool);
948 r_shadow_texturepool = R_AllocTexturePool();
949 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
950 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
952 #define ATTEN2DSIZE 64
953 #define ATTEN3DSIZE 32
954 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
955 r_shadow_blankwhitecubetexture = NULL;
956 r_shadow_normalcubetexture = NULL;
957 if (gl_texturecubemap)
959 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
960 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
961 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
962 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
963 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
964 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
965 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
966 for (side = 0;side < 6;side++)
968 for (y = 0;y < NORMSIZE;y++)
970 for (x = 0;x < NORMSIZE;x++)
972 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
973 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1007 intensity = 127.0f / sqrt(DotProduct(v, v));
1008 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1009 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1010 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1011 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1015 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1017 for (y = 0;y < ATTEN2DSIZE;y++)
1019 for (x = 0;x < ATTEN2DSIZE;x++)
1021 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1022 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1024 intensity = 1.0f - sqrt(DotProduct(v, v));
1026 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1027 d = bound(0, intensity, 255);
1028 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1029 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1030 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1031 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1034 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1035 if (r_shadow_texture3d.integer)
1037 for (z = 0;z < ATTEN3DSIZE;z++)
1039 for (y = 0;y < ATTEN3DSIZE;y++)
1041 for (x = 0;x < ATTEN3DSIZE;x++)
1043 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1044 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1045 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1046 intensity = 1.0f - sqrt(DotProduct(v, v));
1048 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1049 d = bound(0, intensity, 255);
1050 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1051 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1052 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1053 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1057 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1062 void R_Shadow_ValidateCvars(void)
1064 if (r_shadow_texture3d.integer && !gl_texture3d)
1065 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1066 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1067 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1070 void R_Shadow_Stage_Begin(void)
1074 R_Shadow_ValidateCvars();
1076 if (!r_shadow_attenuation2dtexture
1077 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1078 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1079 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1080 R_Shadow_MakeTextures();
1082 memset(&m, 0, sizeof(m));
1083 GL_BlendFunc(GL_ONE, GL_ZERO);
1084 GL_DepthMask(false);
1087 GL_Color(0, 0, 0, 1);
1088 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1089 qglEnable(GL_CULL_FACE);
1090 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1091 r_shadowstage = SHADOWSTAGE_NONE;
1094 void R_Shadow_Stage_ShadowVolumes(void)
1097 memset(&m, 0, sizeof(m));
1099 GL_Color(1, 1, 1, 1);
1100 GL_ColorMask(0, 0, 0, 0);
1101 GL_BlendFunc(GL_ONE, GL_ZERO);
1102 GL_DepthMask(false);
1104 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1105 //if (r_shadow_shadow_polygonoffset.value != 0)
1107 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1108 // qglEnable(GL_POLYGON_OFFSET_FILL);
1111 // qglDisable(GL_POLYGON_OFFSET_FILL);
1112 qglDepthFunc(GL_LESS);
1113 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1114 qglEnable(GL_STENCIL_TEST);
1115 qglStencilFunc(GL_ALWAYS, 128, ~0);
1116 if (gl_ext_stenciltwoside.integer)
1118 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1119 qglDisable(GL_CULL_FACE);
1120 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1121 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1123 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1124 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1126 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1130 r_shadowstage = SHADOWSTAGE_STENCIL;
1131 qglEnable(GL_CULL_FACE);
1133 // this is changed by every shadow render so its value here is unimportant
1134 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1136 GL_Clear(GL_STENCIL_BUFFER_BIT);
1138 // LordHavoc note: many shadow volumes reside entirely inside the world
1139 // (that is to say they are entirely bounded by their lit surfaces),
1140 // which can be optimized by handling things as an inverted light volume,
1141 // with the shadow boundaries of the world being simulated by an altered
1142 // (129) bias to stencil clearing on such lights
1143 // FIXME: generate inverted light volumes for use as shadow volumes and
1144 // optimize for them as noted above
1147 void R_Shadow_Stage_Light(int shadowtest)
1150 memset(&m, 0, sizeof(m));
1152 GL_BlendFunc(GL_ONE, GL_ONE);
1153 GL_DepthMask(false);
1155 qglPolygonOffset(0, 0);
1156 //qglDisable(GL_POLYGON_OFFSET_FILL);
1157 GL_Color(1, 1, 1, 1);
1158 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1159 qglDepthFunc(GL_EQUAL);
1160 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1161 qglEnable(GL_CULL_FACE);
1163 qglEnable(GL_STENCIL_TEST);
1165 qglDisable(GL_STENCIL_TEST);
1166 if (gl_support_stenciltwoside)
1167 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1169 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1170 // only draw light where this geometry was already rendered AND the
1171 // stencil is 128 (values other than this mean shadow)
1172 qglStencilFunc(GL_EQUAL, 128, ~0);
1173 r_shadowstage = SHADOWSTAGE_LIGHT;
1177 void R_Shadow_Stage_End(void)
1180 memset(&m, 0, sizeof(m));
1182 GL_BlendFunc(GL_ONE, GL_ZERO);
1185 qglPolygonOffset(0, 0);
1186 //qglDisable(GL_POLYGON_OFFSET_FILL);
1187 GL_Color(1, 1, 1, 1);
1188 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1189 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1190 qglDepthFunc(GL_LEQUAL);
1191 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1192 qglDisable(GL_STENCIL_TEST);
1193 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1194 if (gl_support_stenciltwoside)
1195 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1197 qglStencilFunc(GL_ALWAYS, 128, ~0);
1198 r_shadowstage = SHADOWSTAGE_NONE;
1201 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1203 int i, ix1, iy1, ix2, iy2;
1204 float x1, y1, x2, y2, x, y, f;
1205 vec3_t smins, smaxs;
1207 if (!r_shadow_scissor.integer)
1209 // if view is inside the box, just say yes it's visible
1210 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1212 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1215 for (i = 0;i < 3;i++)
1217 if (r_viewforward[i] >= 0)
1228 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1229 if (DotProduct(r_viewforward, v2) <= f)
1231 // entirely behind nearclip plane
1234 if (DotProduct(r_viewforward, v) >= f)
1236 // entirely infront of nearclip plane
1237 x1 = y1 = x2 = y2 = 0;
1238 for (i = 0;i < 8;i++)
1240 v[0] = (i & 1) ? mins[0] : maxs[0];
1241 v[1] = (i & 2) ? mins[1] : maxs[1];
1242 v[2] = (i & 4) ? mins[2] : maxs[2];
1244 GL_TransformToScreen(v, v2);
1245 //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]);
1264 // clipped by nearclip plane
1265 // this is nasty and crude...
1266 // create viewspace bbox
1267 for (i = 0;i < 8;i++)
1269 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1270 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1271 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1272 v2[0] = -DotProduct(v, r_viewleft);
1273 v2[1] = DotProduct(v, r_viewup);
1274 v2[2] = DotProduct(v, r_viewforward);
1277 if (smins[0] > v2[0]) smins[0] = v2[0];
1278 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1279 if (smins[1] > v2[1]) smins[1] = v2[1];
1280 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1281 if (smins[2] > v2[2]) smins[2] = v2[2];
1282 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1286 smins[0] = smaxs[0] = v2[0];
1287 smins[1] = smaxs[1] = v2[1];
1288 smins[2] = smaxs[2] = v2[2];
1291 // now we have a bbox in viewspace
1292 // clip it to the view plane
1295 // return true if that culled the box
1296 if (smins[2] >= smaxs[2])
1298 // ok some of it is infront of the view, transform each corner back to
1299 // worldspace and then to screenspace and make screen rect
1300 // initialize these variables just to avoid compiler warnings
1301 x1 = y1 = x2 = y2 = 0;
1302 for (i = 0;i < 8;i++)
1304 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1305 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1306 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1307 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1308 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1309 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1311 GL_TransformToScreen(v, v2);
1312 //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]);
1329 // this code doesn't handle boxes with any points behind view properly
1330 x1 = 1000;x2 = -1000;
1331 y1 = 1000;y2 = -1000;
1332 for (i = 0;i < 8;i++)
1334 v[0] = (i & 1) ? mins[0] : maxs[0];
1335 v[1] = (i & 2) ? mins[1] : maxs[1];
1336 v[2] = (i & 4) ? mins[2] : maxs[2];
1338 GL_TransformToScreen(v, v2);
1339 //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]);
1357 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1358 if (ix1 < r_view_x) ix1 = r_view_x;
1359 if (iy1 < r_view_y) iy1 = r_view_y;
1360 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1361 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1362 if (ix2 <= ix1 || iy2 <= iy1)
1364 // set up the scissor rectangle
1365 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1366 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1367 //qglEnable(GL_SCISSOR_TEST);
1372 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1374 float *color4f = varray_color4f;
1375 float dist, dot, intensity, v[3], n[3];
1376 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1378 Matrix4x4_Transform(m, vertex3f, v);
1379 if ((dist = DotProduct(v, v)) < 1)
1381 Matrix4x4_Transform3x3(m, normal3f, n);
1382 if ((dot = DotProduct(n, v)) > 0)
1385 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1386 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1387 VectorScale(lightcolor, intensity, color4f);
1392 VectorClear(color4f);
1398 VectorClear(color4f);
1404 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1406 float *color4f = varray_color4f;
1407 float dist, dot, intensity, v[3], n[3];
1408 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1410 Matrix4x4_Transform(m, vertex3f, v);
1411 if ((dist = fabs(v[2])) < 1)
1413 Matrix4x4_Transform3x3(m, normal3f, n);
1414 if ((dot = DotProduct(n, v)) > 0)
1416 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1417 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1418 VectorScale(lightcolor, intensity, color4f);
1423 VectorClear(color4f);
1429 VectorClear(color4f);
1435 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1437 float *color4f = varray_color4f;
1438 float dot, intensity, v[3], n[3];
1439 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1441 Matrix4x4_Transform(m, vertex3f, v);
1442 Matrix4x4_Transform3x3(m, normal3f, n);
1443 if ((dot = DotProduct(n, v)) > 0)
1445 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1446 VectorScale(lightcolor, intensity, color4f);
1451 VectorClear(color4f);
1457 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1459 float *color4f = varray_color4f;
1460 float dist, intensity, v[3];
1461 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1463 Matrix4x4_Transform(m, vertex3f, v);
1464 if ((dist = DotProduct(v, v)) < 1)
1467 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1468 VectorScale(lightcolor, intensity, color4f);
1473 VectorClear(color4f);
1479 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1481 float *color4f = varray_color4f;
1482 float dist, intensity, v[3];
1483 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1485 Matrix4x4_Transform(m, vertex3f, v);
1486 if ((dist = fabs(v[2])) < 1)
1488 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1489 VectorScale(lightcolor, intensity, color4f);
1494 VectorClear(color4f);
1500 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1501 #define USETEXMATRIX
1503 #ifndef USETEXMATRIX
1504 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1505 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1506 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1510 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1511 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1512 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1519 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1523 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1524 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1532 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)
1536 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1538 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1539 // the cubemap normalizes this for us
1540 out3f[0] = DotProduct(svector3f, lightdir);
1541 out3f[1] = DotProduct(tvector3f, lightdir);
1542 out3f[2] = DotProduct(normal3f, lightdir);
1546 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)
1549 float lightdir[3], eyedir[3], halfdir[3];
1550 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1552 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1553 VectorNormalizeFast(lightdir);
1554 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1555 VectorNormalizeFast(eyedir);
1556 VectorAdd(lightdir, eyedir, halfdir);
1557 // the cubemap normalizes this for us
1558 out3f[0] = DotProduct(svector3f, halfdir);
1559 out3f[1] = DotProduct(tvector3f, halfdir);
1560 out3f[2] = DotProduct(normal3f, halfdir);
1564 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int visiblelighting)
1567 float color[3], color2[3], colorscale;
1570 basetexture = r_texture_white;
1572 bumptexture = r_texture_blanknormalmap;
1573 if (!lightcolorbase)
1574 lightcolorbase = vec3_origin;
1575 if (!lightcolorpants)
1576 lightcolorpants = vec3_origin;
1577 if (!lightcolorshirt)
1578 lightcolorshirt = vec3_origin;
1579 specularscale *= r_shadow_glossintensity.value;
1582 if (r_shadow_gloss.integer >= 2)
1584 glosstexture = r_texture_white;
1585 specularscale *= r_shadow_gloss2intensity.value;
1589 glosstexture = r_texture_black;
1593 if (r_shadow_gloss.integer < 1)
1596 lightcubemap = r_shadow_blankwhitecubetexture;
1597 if ((ambientscale + diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
1599 if (visiblelighting)
1602 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1603 passes++; // GLSL shader path (GFFX5200, Radeon 9500)
1604 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1606 // TODO: add direct pants/shirt rendering
1607 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1608 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1609 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1610 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1612 bumptexture = r_texture_blanknormalmap;
1614 glosstexture = r_texture_white;
1617 colorscale = ambientscale;
1618 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1621 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1624 else if (r_textureunits.integer >= 4 && lightcubemap)
1627 else if (r_textureunits.integer >= 3 && !lightcubemap)
1632 VectorScale(lightcolorbase, colorscale, color2);
1633 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1638 colorscale = diffusescale;
1639 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1641 // 3/2 3D combine path (Geforce3, Radeon 8500)
1644 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1646 // 1/2/2 3D combine path (original Radeon)
1649 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1651 // 2/2 3D combine path (original Radeon)
1654 else if (r_textureunits.integer >= 4)
1656 // 4/2 2D combine path (Geforce3, Radeon 8500)
1661 // 2/2/2 2D combine path (any dot3 card)
1664 VectorScale(lightcolorbase, colorscale, color2);
1665 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1668 if (specularscale && glosstexture != r_texture_black)
1670 //if (gl_support_blendsquare)
1672 colorscale = specularscale;
1673 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1675 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1679 VectorScale(lightcolorbase, colorscale, color2);
1680 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1687 // TODO: add direct pants/shirt rendering
1688 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1689 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1690 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1691 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1694 VectorScale(lightcolorbase, ambientscale, color2);
1695 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1700 VectorScale(lightcolorbase, diffusescale, color2);
1701 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1707 GL_Color(0.1*passes, 0.025*passes, 0, 1);
1708 memset(&m, 0, sizeof(m));
1709 m.pointer_vertex = vertex3f;
1711 GL_LockArrays(firstvertex, numvertices);
1712 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1713 GL_LockArrays(0, 0);
1717 // FIXME: support EF_NODEPTHTEST
1718 GL_DepthMask(false);
1720 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1722 unsigned int perm, prog;
1723 // GLSL shader path (GFFX5200, Radeon 9500)
1724 memset(&m, 0, sizeof(m));
1725 m.pointer_vertex = vertex3f;
1726 m.pointer_texcoord[0] = texcoord2f;
1727 m.pointer_texcoord3f[1] = svector3f;
1728 m.pointer_texcoord3f[2] = tvector3f;
1729 m.pointer_texcoord3f[3] = normal3f;
1730 m.tex[0] = R_GetTexture(bumptexture);
1731 m.tex[1] = R_GetTexture(basetexture);
1732 m.tex[2] = R_GetTexture(glosstexture);
1733 m.texcubemap[3] = R_GetTexture(lightcubemap);
1734 // TODO: support fog (after renderer is converted to texture fog)
1735 m.tex[4] = R_GetTexture(r_texture_white);
1736 m.texmatrix[3] = *matrix_modeltolight;
1738 GL_BlendFunc(GL_ONE, GL_ONE);
1739 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1742 // only add a feature to the permutation if that permutation exists
1743 // (otherwise it might end up not using a shader at all, which looks
1744 // worse than using less features)
1745 if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
1746 perm |= SHADERPERMUTATION_SPECULAR;
1747 //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
1748 // perm |= SHADERPERMUTATION_FOG;
1749 if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
1750 perm |= SHADERPERMUTATION_CUBEFILTER;
1751 if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
1752 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1753 prog = r_shadow_program_light[perm];
1754 qglUseProgramObjectARB(prog);CHECKGLERROR
1755 // TODO: support fog (after renderer is converted to texture fog)
1756 if (perm & SHADERPERMUTATION_FOG)
1758 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1760 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1761 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1762 if (perm & SHADERPERMUTATION_SPECULAR)
1764 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1765 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1767 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
1768 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1769 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1771 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1773 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1775 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
1776 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
1779 GL_LockArrays(firstvertex, numvertices);
1780 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1782 c_rt_lighttris += numtriangles;
1783 // TODO: add direct pants/shirt rendering
1784 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1786 R_Mesh_TexBind(1, R_GetTexture(pantstexture));
1787 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
1788 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1790 c_rt_lighttris += numtriangles;
1792 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1794 R_Mesh_TexBind(1, R_GetTexture(shirttexture));
1795 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
1796 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1798 c_rt_lighttris += numtriangles;
1800 GL_LockArrays(0, 0);
1801 qglUseProgramObjectARB(0);
1802 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1803 qglBegin(GL_TRIANGLES);
1807 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1809 // TODO: add direct pants/shirt rendering
1810 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
1811 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1812 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
1813 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
1815 bumptexture = r_texture_blanknormalmap;
1817 glosstexture = r_texture_white;
1821 colorscale = ambientscale;
1822 // colorscale accounts for how much we multiply the brightness
1825 // mult is how many times the final pass of the lighting will be
1826 // performed to get more brightness than otherwise possible.
1828 // Limit mult to 64 for sanity sake.
1829 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1831 // 3 3D combine path (Geforce3, Radeon 8500)
1832 memset(&m, 0, sizeof(m));
1833 m.pointer_vertex = vertex3f;
1834 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1836 m.pointer_texcoord3f[0] = vertex3f;
1837 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1839 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1840 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1842 m.tex[1] = R_GetTexture(basetexture);
1843 m.pointer_texcoord[1] = texcoord2f;
1844 m.texcubemap[2] = R_GetTexture(lightcubemap);
1846 m.pointer_texcoord3f[2] = vertex3f;
1847 m.texmatrix[2] = *matrix_modeltolight;
1849 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1850 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1852 GL_BlendFunc(GL_ONE, GL_ONE);
1854 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1856 // 2 3D combine path (Geforce3, original Radeon)
1857 memset(&m, 0, sizeof(m));
1858 m.pointer_vertex = vertex3f;
1859 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1861 m.pointer_texcoord3f[0] = vertex3f;
1862 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1864 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1865 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1867 m.tex[1] = R_GetTexture(basetexture);
1868 m.pointer_texcoord[1] = texcoord2f;
1869 GL_BlendFunc(GL_ONE, GL_ONE);
1871 else if (r_textureunits.integer >= 4 && lightcubemap)
1873 // 4 2D combine path (Geforce3, Radeon 8500)
1874 memset(&m, 0, sizeof(m));
1875 m.pointer_vertex = vertex3f;
1876 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1878 m.pointer_texcoord3f[0] = vertex3f;
1879 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1881 m.pointer_texcoord[0] = varray_texcoord2f[0];
1882 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1884 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1886 m.pointer_texcoord3f[1] = vertex3f;
1887 m.texmatrix[1] = *matrix_modeltoattenuationz;
1889 m.pointer_texcoord[1] = varray_texcoord2f[1];
1890 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1892 m.tex[2] = R_GetTexture(basetexture);
1893 m.pointer_texcoord[2] = texcoord2f;
1896 m.texcubemap[3] = R_GetTexture(lightcubemap);
1898 m.pointer_texcoord3f[3] = vertex3f;
1899 m.texmatrix[3] = *matrix_modeltolight;
1901 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1902 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1905 GL_BlendFunc(GL_ONE, GL_ONE);
1907 else if (r_textureunits.integer >= 3 && !lightcubemap)
1909 // 3 2D combine path (Geforce3, original Radeon)
1910 memset(&m, 0, sizeof(m));
1911 m.pointer_vertex = vertex3f;
1912 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1914 m.pointer_texcoord3f[0] = vertex3f;
1915 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1917 m.pointer_texcoord[0] = varray_texcoord2f[0];
1918 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1920 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1922 m.pointer_texcoord3f[1] = vertex3f;
1923 m.texmatrix[1] = *matrix_modeltoattenuationz;
1925 m.pointer_texcoord[1] = varray_texcoord2f[1];
1926 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1928 m.tex[2] = R_GetTexture(basetexture);
1929 m.pointer_texcoord[2] = texcoord2f;
1930 GL_BlendFunc(GL_ONE, GL_ONE);
1934 // 2/2/2 2D combine path (any dot3 card)
1935 memset(&m, 0, sizeof(m));
1936 m.pointer_vertex = vertex3f;
1937 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1939 m.pointer_texcoord3f[0] = vertex3f;
1940 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1942 m.pointer_texcoord[0] = varray_texcoord2f[0];
1943 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
1945 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1947 m.pointer_texcoord3f[1] = vertex3f;
1948 m.texmatrix[1] = *matrix_modeltoattenuationz;
1950 m.pointer_texcoord[1] = varray_texcoord2f[1];
1951 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
1954 GL_ColorMask(0,0,0,1);
1955 GL_BlendFunc(GL_ONE, GL_ZERO);
1956 GL_LockArrays(firstvertex, numvertices);
1957 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1958 GL_LockArrays(0, 0);
1960 c_rt_lighttris += numtriangles;
1962 memset(&m, 0, sizeof(m));
1963 m.pointer_vertex = vertex3f;
1964 m.tex[0] = R_GetTexture(basetexture);
1965 m.pointer_texcoord[0] = texcoord2f;
1968 m.texcubemap[1] = R_GetTexture(lightcubemap);
1970 m.pointer_texcoord3f[1] = vertex3f;
1971 m.texmatrix[1] = *matrix_modeltolight;
1973 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1974 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
1977 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1979 // this final code is shared
1981 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1982 VectorScale(lightcolorbase, colorscale, color2);
1983 GL_LockArrays(firstvertex, numvertices);
1984 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1986 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1987 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
1989 c_rt_lighttris += numtriangles;
1991 GL_LockArrays(0, 0);
1996 colorscale = diffusescale;
1997 // colorscale accounts for how much we multiply the brightness
2000 // mult is how many times the final pass of the lighting will be
2001 // performed to get more brightness than otherwise possible.
2003 // Limit mult to 64 for sanity sake.
2004 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2006 // 3/2 3D combine path (Geforce3, Radeon 8500)
2007 memset(&m, 0, sizeof(m));
2008 m.pointer_vertex = vertex3f;
2009 m.tex[0] = R_GetTexture(bumptexture);
2010 m.texcombinergb[0] = GL_REPLACE;
2011 m.pointer_texcoord[0] = texcoord2f;
2012 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2013 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2014 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2015 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2016 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2018 m.pointer_texcoord3f[2] = vertex3f;
2019 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2021 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
2022 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2025 GL_ColorMask(0,0,0,1);
2026 GL_BlendFunc(GL_ONE, GL_ZERO);
2027 GL_LockArrays(firstvertex, numvertices);
2028 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2029 GL_LockArrays(0, 0);
2031 c_rt_lighttris += numtriangles;
2033 memset(&m, 0, sizeof(m));
2034 m.pointer_vertex = vertex3f;
2035 m.tex[0] = R_GetTexture(basetexture);
2036 m.pointer_texcoord[0] = texcoord2f;
2039 m.texcubemap[1] = R_GetTexture(lightcubemap);
2041 m.pointer_texcoord3f[1] = vertex3f;
2042 m.texmatrix[1] = *matrix_modeltolight;
2044 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2045 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2048 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2050 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
2052 // 1/2/2 3D combine path (original Radeon)
2053 memset(&m, 0, sizeof(m));
2054 m.pointer_vertex = vertex3f;
2055 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2057 m.pointer_texcoord3f[0] = vertex3f;
2058 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2060 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2061 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2064 GL_ColorMask(0,0,0,1);
2065 GL_BlendFunc(GL_ONE, GL_ZERO);
2066 GL_LockArrays(firstvertex, numvertices);
2067 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2068 GL_LockArrays(0, 0);
2070 c_rt_lighttris += numtriangles;
2072 memset(&m, 0, sizeof(m));
2073 m.pointer_vertex = vertex3f;
2074 m.tex[0] = R_GetTexture(bumptexture);
2075 m.texcombinergb[0] = GL_REPLACE;
2076 m.pointer_texcoord[0] = texcoord2f;
2077 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2078 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2079 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2080 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2082 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2083 GL_LockArrays(firstvertex, numvertices);
2084 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2085 GL_LockArrays(0, 0);
2087 c_rt_lighttris += numtriangles;
2089 memset(&m, 0, sizeof(m));
2090 m.pointer_vertex = vertex3f;
2091 m.tex[0] = R_GetTexture(basetexture);
2092 m.pointer_texcoord[0] = texcoord2f;
2095 m.texcubemap[1] = R_GetTexture(lightcubemap);
2097 m.pointer_texcoord3f[1] = vertex3f;
2098 m.texmatrix[1] = *matrix_modeltolight;
2100 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2101 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2104 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2106 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
2108 // 2/2 3D combine path (original Radeon)
2109 memset(&m, 0, sizeof(m));
2110 m.pointer_vertex = vertex3f;
2111 m.tex[0] = R_GetTexture(bumptexture);
2112 m.texcombinergb[0] = GL_REPLACE;
2113 m.pointer_texcoord[0] = texcoord2f;
2114 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2115 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2116 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2117 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2119 GL_ColorMask(0,0,0,1);
2120 GL_BlendFunc(GL_ONE, GL_ZERO);
2121 GL_LockArrays(firstvertex, numvertices);
2122 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2123 GL_LockArrays(0, 0);
2125 c_rt_lighttris += numtriangles;
2127 memset(&m, 0, sizeof(m));
2128 m.pointer_vertex = vertex3f;
2129 m.tex[0] = R_GetTexture(basetexture);
2130 m.pointer_texcoord[0] = texcoord2f;
2131 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2133 m.pointer_texcoord3f[1] = vertex3f;
2134 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2136 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2137 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2139 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2141 else if (r_textureunits.integer >= 4)
2143 // 4/2 2D combine path (Geforce3, Radeon 8500)
2144 memset(&m, 0, sizeof(m));
2145 m.pointer_vertex = vertex3f;
2146 m.tex[0] = R_GetTexture(bumptexture);
2147 m.texcombinergb[0] = GL_REPLACE;
2148 m.pointer_texcoord[0] = texcoord2f;
2149 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2150 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2151 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2152 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2153 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2155 m.pointer_texcoord3f[2] = vertex3f;
2156 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2158 m.pointer_texcoord[2] = varray_texcoord2f[2];
2159 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2161 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2163 m.pointer_texcoord3f[3] = vertex3f;
2164 m.texmatrix[3] = *matrix_modeltoattenuationz;
2166 m.pointer_texcoord[3] = varray_texcoord2f[3];
2167 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2170 GL_ColorMask(0,0,0,1);
2171 GL_BlendFunc(GL_ONE, GL_ZERO);
2172 GL_LockArrays(firstvertex, numvertices);
2173 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2174 GL_LockArrays(0, 0);
2176 c_rt_lighttris += numtriangles;
2178 memset(&m, 0, sizeof(m));
2179 m.pointer_vertex = vertex3f;
2180 m.tex[0] = R_GetTexture(basetexture);
2181 m.pointer_texcoord[0] = texcoord2f;
2184 m.texcubemap[1] = R_GetTexture(lightcubemap);
2186 m.pointer_texcoord3f[1] = vertex3f;
2187 m.texmatrix[1] = *matrix_modeltolight;
2189 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2190 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2193 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2197 // 2/2/2 2D combine path (any dot3 card)
2198 memset(&m, 0, sizeof(m));
2199 m.pointer_vertex = vertex3f;
2200 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2202 m.pointer_texcoord3f[0] = vertex3f;
2203 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2205 m.pointer_texcoord[0] = varray_texcoord2f[0];
2206 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2208 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2210 m.pointer_texcoord3f[1] = vertex3f;
2211 m.texmatrix[1] = *matrix_modeltoattenuationz;
2213 m.pointer_texcoord[1] = varray_texcoord2f[1];
2214 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2217 GL_ColorMask(0,0,0,1);
2218 GL_BlendFunc(GL_ONE, GL_ZERO);
2219 GL_LockArrays(firstvertex, numvertices);
2220 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2221 GL_LockArrays(0, 0);
2223 c_rt_lighttris += numtriangles;
2225 memset(&m, 0, sizeof(m));
2226 m.pointer_vertex = vertex3f;
2227 m.tex[0] = R_GetTexture(bumptexture);
2228 m.texcombinergb[0] = GL_REPLACE;
2229 m.pointer_texcoord[0] = texcoord2f;
2230 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2231 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2232 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2233 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
2235 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2236 GL_LockArrays(firstvertex, numvertices);
2237 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2238 GL_LockArrays(0, 0);
2240 c_rt_lighttris += numtriangles;
2242 memset(&m, 0, sizeof(m));
2243 m.pointer_vertex = vertex3f;
2244 m.tex[0] = R_GetTexture(basetexture);
2245 m.pointer_texcoord[0] = texcoord2f;
2248 m.texcubemap[1] = R_GetTexture(lightcubemap);
2250 m.pointer_texcoord3f[1] = vertex3f;
2251 m.texmatrix[1] = *matrix_modeltolight;
2253 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2254 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2257 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2259 // this final code is shared
2261 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2262 VectorScale(lightcolorbase, colorscale, color2);
2263 GL_LockArrays(firstvertex, numvertices);
2264 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2266 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2267 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2269 c_rt_lighttris += numtriangles;
2271 GL_LockArrays(0, 0);
2273 if (specularscale && glosstexture != r_texture_black)
2275 // FIXME: detect blendsquare!
2276 //if (gl_support_blendsquare)
2278 colorscale = specularscale;
2280 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2282 // 2/0/0/1/2 3D combine blendsquare path
2283 memset(&m, 0, sizeof(m));
2284 m.pointer_vertex = vertex3f;
2285 m.tex[0] = R_GetTexture(bumptexture);
2286 m.pointer_texcoord[0] = texcoord2f;
2287 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2288 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2289 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2290 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2292 GL_ColorMask(0,0,0,1);
2293 // this squares the result
2294 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2295 GL_LockArrays(firstvertex, numvertices);
2296 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2297 GL_LockArrays(0, 0);
2299 c_rt_lighttris += numtriangles;
2301 memset(&m, 0, sizeof(m));
2302 m.pointer_vertex = vertex3f;
2304 GL_LockArrays(firstvertex, numvertices);
2305 // square alpha in framebuffer a few times to make it shiny
2306 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2307 // these comments are a test run through this math for intensity 0.5
2308 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2309 // 0.25 * 0.25 = 0.0625 (this is another pass)
2310 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2311 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2313 c_rt_lighttris += numtriangles;
2314 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2316 c_rt_lighttris += numtriangles;
2317 GL_LockArrays(0, 0);
2319 memset(&m, 0, sizeof(m));
2320 m.pointer_vertex = vertex3f;
2321 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2323 m.pointer_texcoord3f[0] = vertex3f;
2324 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2326 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2327 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2330 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2331 GL_LockArrays(firstvertex, numvertices);
2332 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2333 GL_LockArrays(0, 0);
2335 c_rt_lighttris += numtriangles;
2337 memset(&m, 0, sizeof(m));
2338 m.pointer_vertex = vertex3f;
2339 m.tex[0] = R_GetTexture(glosstexture);
2340 m.pointer_texcoord[0] = texcoord2f;
2343 m.texcubemap[1] = R_GetTexture(lightcubemap);
2345 m.pointer_texcoord3f[1] = vertex3f;
2346 m.texmatrix[1] = *matrix_modeltolight;
2348 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2349 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2352 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2354 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2356 // 2/0/0/2 3D combine blendsquare path
2357 memset(&m, 0, sizeof(m));
2358 m.pointer_vertex = vertex3f;
2359 m.tex[0] = R_GetTexture(bumptexture);
2360 m.pointer_texcoord[0] = texcoord2f;
2361 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2362 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2363 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2364 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2366 GL_ColorMask(0,0,0,1);
2367 // this squares the result
2368 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2369 GL_LockArrays(firstvertex, numvertices);
2370 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2371 GL_LockArrays(0, 0);
2373 c_rt_lighttris += numtriangles;
2375 memset(&m, 0, sizeof(m));
2376 m.pointer_vertex = vertex3f;
2378 GL_LockArrays(firstvertex, numvertices);
2379 // square alpha in framebuffer a few times to make it shiny
2380 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2381 // these comments are a test run through this math for intensity 0.5
2382 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2383 // 0.25 * 0.25 = 0.0625 (this is another pass)
2384 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2385 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2387 c_rt_lighttris += numtriangles;
2388 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2390 c_rt_lighttris += numtriangles;
2391 GL_LockArrays(0, 0);
2393 memset(&m, 0, sizeof(m));
2394 m.pointer_vertex = vertex3f;
2395 m.tex[0] = R_GetTexture(glosstexture);
2396 m.pointer_texcoord[0] = texcoord2f;
2397 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2399 m.pointer_texcoord3f[1] = vertex3f;
2400 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2402 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2403 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2405 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2409 // 2/0/0/2/2 2D combine blendsquare path
2410 memset(&m, 0, sizeof(m));
2411 m.pointer_vertex = vertex3f;
2412 m.tex[0] = R_GetTexture(bumptexture);
2413 m.pointer_texcoord[0] = texcoord2f;
2414 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2415 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2416 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2417 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
2419 GL_ColorMask(0,0,0,1);
2420 // this squares the result
2421 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2422 GL_LockArrays(firstvertex, numvertices);
2423 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2424 GL_LockArrays(0, 0);
2426 c_rt_lighttris += numtriangles;
2428 memset(&m, 0, sizeof(m));
2429 m.pointer_vertex = vertex3f;
2431 GL_LockArrays(firstvertex, numvertices);
2432 // square alpha in framebuffer a few times to make it shiny
2433 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2434 // these comments are a test run through this math for intensity 0.5
2435 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2436 // 0.25 * 0.25 = 0.0625 (this is another pass)
2437 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2438 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2440 c_rt_lighttris += numtriangles;
2441 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2443 c_rt_lighttris += numtriangles;
2444 GL_LockArrays(0, 0);
2446 memset(&m, 0, sizeof(m));
2447 m.pointer_vertex = vertex3f;
2448 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2450 m.pointer_texcoord3f[0] = vertex3f;
2451 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2453 m.pointer_texcoord[0] = varray_texcoord2f[0];
2454 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2456 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2458 m.pointer_texcoord3f[1] = vertex3f;
2459 m.texmatrix[1] = *matrix_modeltoattenuationz;
2461 m.pointer_texcoord[1] = varray_texcoord2f[1];
2462 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2465 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2466 GL_LockArrays(firstvertex, numvertices);
2467 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2468 GL_LockArrays(0, 0);
2470 c_rt_lighttris += numtriangles;
2472 memset(&m, 0, sizeof(m));
2473 m.pointer_vertex = vertex3f;
2474 m.tex[0] = R_GetTexture(glosstexture);
2475 m.pointer_texcoord[0] = texcoord2f;
2478 m.texcubemap[1] = R_GetTexture(lightcubemap);
2480 m.pointer_texcoord3f[1] = vertex3f;
2481 m.texmatrix[1] = *matrix_modeltolight;
2483 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2484 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
2487 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2490 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2491 VectorScale(lightcolorbase, colorscale, color2);
2492 GL_LockArrays(firstvertex, numvertices);
2493 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2495 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2496 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2498 c_rt_lighttris += numtriangles;
2500 GL_LockArrays(0, 0);
2506 // TODO: add direct pants/shirt rendering
2507 if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
2508 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
2509 if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
2510 R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
2513 GL_BlendFunc(GL_ONE, GL_ONE);
2514 VectorScale(lightcolorbase, ambientscale, color2);
2515 memset(&m, 0, sizeof(m));
2516 m.pointer_vertex = vertex3f;
2517 m.tex[0] = R_GetTexture(basetexture);
2518 m.pointer_texcoord[0] = texcoord2f;
2519 if (r_textureunits.integer >= 2)
2522 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2524 m.pointer_texcoord3f[1] = vertex3f;
2525 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2527 m.pointer_texcoord[1] = varray_texcoord2f[1];
2528 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2530 if (r_textureunits.integer >= 3)
2532 // Geforce3/Radeon class but not using dot3
2533 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2535 m.pointer_texcoord3f[2] = vertex3f;
2536 m.texmatrix[2] = *matrix_modeltoattenuationz;
2538 m.pointer_texcoord[2] = varray_texcoord2f[2];
2539 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2543 if (r_textureunits.integer >= 3)
2544 m.pointer_color = NULL;
2546 m.pointer_color = varray_color4f;
2548 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2550 color[0] = bound(0, color2[0], 1);
2551 color[1] = bound(0, color2[1], 1);
2552 color[2] = bound(0, color2[2], 1);
2553 if (r_textureunits.integer >= 3)
2554 GL_Color(color[0], color[1], color[2], 1);
2555 else if (r_textureunits.integer >= 2)
2556 R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2558 R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
2559 GL_LockArrays(firstvertex, numvertices);
2560 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2561 GL_LockArrays(0, 0);
2563 c_rt_lighttris += numtriangles;
2568 GL_BlendFunc(GL_ONE, GL_ONE);
2569 VectorScale(lightcolorbase, diffusescale, color2);
2570 memset(&m, 0, sizeof(m));
2571 m.pointer_vertex = vertex3f;
2572 m.pointer_color = varray_color4f;
2573 m.tex[0] = R_GetTexture(basetexture);
2574 m.pointer_texcoord[0] = texcoord2f;
2575 if (r_textureunits.integer >= 2)
2578 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2580 m.pointer_texcoord3f[1] = vertex3f;
2581 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2583 m.pointer_texcoord[1] = varray_texcoord2f[1];
2584 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
2586 if (r_textureunits.integer >= 3)
2588 // Geforce3/Radeon class but not using dot3
2589 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2591 m.pointer_texcoord3f[2] = vertex3f;
2592 m.texmatrix[2] = *matrix_modeltoattenuationz;
2594 m.pointer_texcoord[2] = varray_texcoord2f[2];
2595 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
2600 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2602 color[0] = bound(0, color2[0], 1);
2603 color[1] = bound(0, color2[1], 1);
2604 color[2] = bound(0, color2[2], 1);
2605 if (r_textureunits.integer >= 3)
2606 R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2607 else if (r_textureunits.integer >= 2)
2608 R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2610 R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
2611 GL_LockArrays(firstvertex, numvertices);
2612 R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
2613 GL_LockArrays(0, 0);
2615 c_rt_lighttris += numtriangles;
2621 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2625 R_RTLight_Uncompile(rtlight);
2626 memset(rtlight, 0, sizeof(*rtlight));
2628 VectorCopy(light->origin, rtlight->shadoworigin);
2629 VectorCopy(light->color, rtlight->color);
2630 rtlight->radius = light->radius;
2631 //rtlight->cullradius = rtlight->radius;
2632 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2633 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2634 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2635 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2636 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2637 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2638 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2639 rtlight->cubemapname[0] = 0;
2640 if (light->cubemapname[0])
2641 strcpy(rtlight->cubemapname, light->cubemapname);
2642 else if (light->cubemapnum > 0)
2643 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2644 rtlight->shadow = light->shadow;
2645 rtlight->corona = light->corona;
2646 rtlight->style = light->style;
2647 rtlight->isstatic = isstatic;
2648 rtlight->coronasizescale = light->coronasizescale;
2649 rtlight->ambientscale = light->ambientscale;
2650 rtlight->diffusescale = light->diffusescale;
2651 rtlight->specularscale = light->specularscale;
2652 rtlight->flags = light->flags;
2653 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2654 // ConcatScale won't work here because this needs to scale rotate and
2655 // translate, not just rotate
2656 scale = 1.0f / rtlight->radius;
2657 for (k = 0;k < 3;k++)
2658 for (j = 0;j < 4;j++)
2659 rtlight->matrix_worldtolight.m[k][j] *= scale;
2660 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2661 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2663 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2664 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2665 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2666 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2669 // compiles rtlight geometry
2670 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2671 void R_RTLight_Compile(rtlight_t *rtlight)
2673 int shadowmeshes, shadowtris, lightmeshes, lighttris, numleafs, numleafpvsbytes, numsurfaces;
2674 entity_render_t *ent = r_refdef.worldentity;
2675 model_t *model = r_refdef.worldmodel;
2678 // compile the light
2679 rtlight->compiled = true;
2680 rtlight->static_numleafs = 0;
2681 rtlight->static_numleafpvsbytes = 0;
2682 rtlight->static_leaflist = NULL;
2683 rtlight->static_leafpvs = NULL;
2684 rtlight->static_numsurfaces = 0;
2685 rtlight->static_surfacelist = NULL;
2686 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2687 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2688 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2689 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2690 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2691 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2693 if (model && model->GetLightInfo)
2695 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2696 r_shadow_compilingrtlight = rtlight;
2697 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->brush.num_surfaces);
2698 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);
2699 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2700 data = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2701 rtlight->static_numleafs = numleafs;
2702 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2703 rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
2704 rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
2705 rtlight->static_numsurfaces = numsurfaces;
2706 rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
2708 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2709 if (numleafpvsbytes)
2710 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2712 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2713 if (model->DrawShadowVolume && rtlight->shadow)
2715 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2716 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2717 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2719 if (model->DrawLight)
2721 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2722 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, 0, 0, 0, numsurfaces, r_shadow_buffer_surfacelist, 0);
2723 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2725 // switch back to rendering when DrawShadowVolume or DrawLight is called
2726 r_shadow_compilingrtlight = NULL;
2730 // use smallest available cullradius - box radius or light radius
2731 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2732 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2736 if (rtlight->static_meshchain_shadow)
2739 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2742 shadowtris += mesh->numtriangles;
2748 if (rtlight->static_meshchain_light)
2751 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2754 lighttris += mesh->numtriangles;
2758 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes), %i light triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes, lighttris, lightmeshes);
2761 void R_RTLight_Uncompile(rtlight_t *rtlight)
2763 if (rtlight->compiled)
2765 if (rtlight->static_meshchain_shadow)
2766 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2767 rtlight->static_meshchain_shadow = NULL;
2768 if (rtlight->static_meshchain_light)
2769 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2770 rtlight->static_meshchain_light = NULL;
2771 // these allocations are grouped
2772 if (rtlight->static_leaflist)
2773 Mem_Free(rtlight->static_leaflist);
2774 rtlight->static_numleafs = 0;
2775 rtlight->static_numleafpvsbytes = 0;
2776 rtlight->static_leaflist = NULL;
2777 rtlight->static_leafpvs = NULL;
2778 rtlight->static_numsurfaces = 0;
2779 rtlight->static_surfacelist = NULL;
2780 rtlight->compiled = false;
2784 void R_Shadow_UncompileWorldLights(void)
2787 for (light = r_shadow_worldlightchain;light;light = light->next)
2788 R_RTLight_Uncompile(&light->rtlight);
2791 void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
2793 int i, shadow, usestencil;
2794 entity_render_t *ent;
2796 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2797 rtexture_t *cubemaptexture;
2798 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2799 int numleafs, numsurfaces;
2800 int *leaflist, *surfacelist;
2802 vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
2806 // skip lights that don't light (corona only lights)
2807 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2810 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2811 VectorScale(rtlight->color, f, lightcolor);
2812 if (VectorLength2(lightcolor) < 0.01)
2815 if (rtlight->selected)
2817 f = 2 + sin(realtime * M_PI * 4.0);
2818 VectorScale(lightcolor, f, lightcolor);
2822 // loading is done before visibility checks because loading should happen
2823 // all at once at the start of a level, not when it stalls gameplay.
2824 // (especially important to benchmarks)
2825 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2826 R_RTLight_Compile(rtlight);
2827 if (rtlight->cubemapname[0])
2828 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2830 cubemaptexture = NULL;
2832 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2833 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2834 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2835 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2836 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2837 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2838 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2845 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2847 // compiled light, world available and can receive realtime lighting
2848 // retrieve leaf information
2849 numleafs = rtlight->static_numleafs;
2850 leaflist = rtlight->static_leaflist;
2851 leafpvs = rtlight->static_leafpvs;
2852 numsurfaces = rtlight->static_numsurfaces;
2853 surfacelist = rtlight->static_surfacelist;
2854 VectorCopy(rtlight->cullmins, cullmins);
2855 VectorCopy(rtlight->cullmaxs, cullmaxs);
2857 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2859 // dynamic light, world available and can receive realtime lighting
2860 // if the light box is offscreen, skip it right away
2861 if (R_CullBox(cullmins, cullmaxs))
2863 // calculate lit surfaces and leafs
2864 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
2865 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2866 leaflist = r_shadow_buffer_leaflist;
2867 leafpvs = r_shadow_buffer_leafpvs;
2868 surfacelist = r_shadow_buffer_surfacelist;
2870 // if the reduced leaf bounds are offscreen, skip it
2871 if (R_CullBox(cullmins, cullmaxs))
2873 // check if light is illuminating any visible leafs
2876 for (i = 0;i < numleafs;i++)
2877 if (r_worldleafvisible[leaflist[i]])
2882 // set up a scissor rectangle for this light
2883 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2886 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2889 if (shadow && ((gl_stencil && !visiblelighting) || visiblevolumes))
2893 qglDisable(GL_CULL_FACE);
2894 GL_DepthTest(visiblevolumes < 2);
2895 GL_Color(0.0, 0.0125, 0.1, 1);
2899 R_Shadow_Stage_ShadowVolumes();
2902 ent = r_refdef.worldentity;
2903 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2905 memset(&m, 0, sizeof(m));
2906 R_Mesh_Matrix(&ent->matrix);
2907 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2909 m.pointer_vertex = mesh->vertex3f;
2911 GL_LockArrays(0, mesh->numverts);
2912 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2914 // increment stencil if backface is behind depthbuffer
2915 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2916 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2917 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2918 c_rtcached_shadowmeshes++;
2919 c_rtcached_shadowtris += mesh->numtriangles;
2920 // decrement stencil if frontface is behind depthbuffer
2921 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2922 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2924 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2925 c_rtcached_shadowmeshes++;
2926 c_rtcached_shadowtris += mesh->numtriangles;
2927 GL_LockArrays(0, 0);
2930 else if (numsurfaces)
2932 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2933 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
2935 if (r_drawentities.integer)
2937 for (i = 0;i < r_refdef.numentities;i++)
2939 ent = r_refdef.entities[i];
2941 if (r_shadow_cull.integer)
2943 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2945 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingLeafPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2948 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2950 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2951 // light emitting entities should not cast their own shadow
2952 if (VectorLength2(relativelightorigin) < 0.1)
2954 relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
2955 relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
2956 relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
2957 relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
2958 relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
2959 relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
2960 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
2965 if (visiblelighting || !visiblevolumes)
2967 if (visiblelighting)
2969 qglEnable(GL_CULL_FACE);
2970 GL_DepthTest(visiblelighting < 2);
2971 GL_Color(0.1, 0.0125, 0, 1);
2974 R_Shadow_Stage_Light(usestencil);
2976 ent = r_refdef.worldentity;
2977 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2979 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2980 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2981 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2982 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2983 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2984 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2985 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2986 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2987 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
2989 R_Mesh_Matrix(&ent->matrix);
2990 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2991 R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, NULL, NULL, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, visiblelighting);
2994 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist, visiblelighting);
2996 if (r_drawentities.integer)
2998 for (i = 0;i < r_refdef.numentities;i++)
3000 ent = r_refdef.entities[i];
3001 // can't draw transparent entity lighting here because
3002 // transparent meshes are deferred for later
3003 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
3005 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
3006 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
3007 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
3008 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
3009 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
3010 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
3011 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
3012 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
3013 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, ent->model->nummodelsurfaces, ent->model->surfacelist, visiblelighting);
3020 void R_ShadowVolumeLighting(int visiblelighting, int visiblevolumes)
3026 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3027 R_Shadow_EditLights_Reload_f();
3029 if (visiblelighting || visiblevolumes)
3031 memset(&m, 0, sizeof(m));
3034 GL_BlendFunc(GL_ONE, GL_ONE);
3035 GL_DepthMask(false);
3036 qglCullFace(GL_FRONT); // this culls back
3039 R_Shadow_Stage_Begin();
3040 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3041 if (r_shadow_debuglight.integer >= 0)
3043 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3044 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3045 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
3048 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3049 if (light->flags & flag)
3050 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
3052 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
3053 R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
3055 if (visiblelighting || visiblevolumes)
3057 qglEnable(GL_CULL_FACE);
3058 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
3061 R_Shadow_Stage_End();
3064 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3065 typedef struct suffixinfo_s
3068 qboolean flipx, flipy, flipdiagonal;
3071 static suffixinfo_t suffix[3][6] =
3074 {"px", false, false, false},
3075 {"nx", false, false, false},
3076 {"py", false, false, false},
3077 {"ny", false, false, false},
3078 {"pz", false, false, false},
3079 {"nz", false, false, false}
3082 {"posx", false, false, false},
3083 {"negx", false, false, false},
3084 {"posy", false, false, false},
3085 {"negy", false, false, false},
3086 {"posz", false, false, false},
3087 {"negz", false, false, false}
3090 {"rt", true, false, true},
3091 {"lf", false, true, true},
3092 {"ft", true, true, false},
3093 {"bk", false, false, false},
3094 {"up", true, false, true},
3095 {"dn", true, false, true}
3099 static int componentorder[4] = {0, 1, 2, 3};
3101 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3103 int i, j, cubemapsize;
3104 qbyte *cubemappixels, *image_rgba;
3105 rtexture_t *cubemaptexture;
3107 // must start 0 so the first loadimagepixels has no requested width/height
3109 cubemappixels = NULL;
3110 cubemaptexture = NULL;
3111 // keep trying different suffix groups (posx, px, rt) until one loads
3112 for (j = 0;j < 3 && !cubemappixels;j++)
3114 // load the 6 images in the suffix group
3115 for (i = 0;i < 6;i++)
3117 // generate an image name based on the base and and suffix
3118 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3120 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3122 // an image loaded, make sure width and height are equal
3123 if (image_width == image_height)
3125 // if this is the first image to load successfully, allocate the cubemap memory
3126 if (!cubemappixels && image_width >= 1)
3128 cubemapsize = image_width;
3129 // note this clears to black, so unavailable sides are black
3130 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3132 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3134 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);
3137 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3139 Mem_Free(image_rgba);
3143 // if a cubemap loaded, upload it
3146 if (!r_shadow_filters_texturepool)
3147 r_shadow_filters_texturepool = R_AllocTexturePool();
3148 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3149 Mem_Free(cubemappixels);
3153 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3154 for (j = 0;j < 3;j++)
3155 for (i = 0;i < 6;i++)
3156 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3157 Con_Print(" and was unable to find any of them.\n");
3159 return cubemaptexture;
3162 rtexture_t *R_Shadow_Cubemap(const char *basename)
3165 for (i = 0;i < numcubemaps;i++)
3166 if (!strcasecmp(cubemaps[i].basename, basename))
3167 return cubemaps[i].texture;
3168 if (i >= MAX_CUBEMAPS)
3171 strcpy(cubemaps[i].basename, basename);
3172 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3173 return cubemaps[i].texture;
3176 void R_Shadow_FreeCubemaps(void)
3179 R_FreeTexturePool(&r_shadow_filters_texturepool);
3182 dlight_t *R_Shadow_NewWorldLight(void)
3185 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3186 light->next = r_shadow_worldlightchain;
3187 r_shadow_worldlightchain = light;
3191 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)
3193 VectorCopy(origin, light->origin);
3194 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3195 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3196 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3197 light->color[0] = max(color[0], 0);
3198 light->color[1] = max(color[1], 0);
3199 light->color[2] = max(color[2], 0);
3200 light->radius = max(radius, 0);
3201 light->style = style;
3202 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3204 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3207 light->shadow = shadowenable;
3208 light->corona = corona;
3211 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3212 light->coronasizescale = coronasizescale;
3213 light->ambientscale = ambientscale;
3214 light->diffusescale = diffusescale;
3215 light->specularscale = specularscale;
3216 light->flags = flags;
3217 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3219 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3222 void R_Shadow_FreeWorldLight(dlight_t *light)
3224 dlight_t **lightpointer;
3225 R_RTLight_Uncompile(&light->rtlight);
3226 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3227 if (*lightpointer != light)
3228 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3229 *lightpointer = light->next;
3233 void R_Shadow_ClearWorldLights(void)
3235 while (r_shadow_worldlightchain)
3236 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3237 r_shadow_selectedlight = NULL;
3238 R_Shadow_FreeCubemaps();
3241 void R_Shadow_SelectLight(dlight_t *light)
3243 if (r_shadow_selectedlight)
3244 r_shadow_selectedlight->selected = false;
3245 r_shadow_selectedlight = light;
3246 if (r_shadow_selectedlight)
3247 r_shadow_selectedlight->selected = true;
3250 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3252 float scale = r_editlights_cursorgrid.value * 0.5f;
3253 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);
3256 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3259 const dlight_t *light;
3262 if (light->selected)
3263 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3266 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);
3269 void R_Shadow_DrawLightSprites(void)
3275 for (i = 0;i < 5;i++)
3277 lighttextures[i] = NULL;
3278 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
3279 lighttextures[i] = pic->tex;
3282 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3283 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3284 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3287 void R_Shadow_SelectLightInView(void)
3289 float bestrating, rating, temp[3];
3290 dlight_t *best, *light;
3293 for (light = r_shadow_worldlightchain;light;light = light->next)
3295 VectorSubtract(light->origin, r_vieworigin, temp);
3296 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3299 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3300 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3302 bestrating = rating;
3307 R_Shadow_SelectLight(best);
3310 void R_Shadow_LoadWorldLights(void)
3312 int n, a, style, shadow, flags;
3313 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3314 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3315 if (r_refdef.worldmodel == NULL)
3317 Con_Print("No map loaded.\n");
3320 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3321 strlcat (name, ".rtlights", sizeof (name));
3322 lightsstring = FS_LoadFile(name, tempmempool, false);
3332 for (;COM_Parse(t, true) && strcmp(
3333 if (COM_Parse(t, true))
3335 if (com_token[0] == '!')
3338 origin[0] = atof(com_token+1);
3341 origin[0] = atof(com_token);
3346 while (*s && *s != '\n' && *s != '\r')
3352 // check for modifier flags
3359 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);
3362 flags = LIGHTFLAG_REALTIMEMODE;
3370 coronasizescale = 0.25f;
3372 VectorClear(angles);
3375 if (a < 9 || !strcmp(cubemapname, "\"\""))
3377 // remove quotes on cubemapname
3378 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3380 cubemapname[strlen(cubemapname)-1] = 0;
3381 strcpy(cubemapname, cubemapname + 1);
3385 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);
3388 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3389 radius *= r_editlights_rtlightssizescale.value;
3390 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3398 Con_Printf("invalid rtlights file \"%s\"\n", name);
3399 Mem_Free(lightsstring);
3403 void R_Shadow_SaveWorldLights(void)
3406 int bufchars, bufmaxchars;
3408 char name[MAX_QPATH];
3410 if (!r_shadow_worldlightchain)
3412 if (r_refdef.worldmodel == NULL)
3414 Con_Print("No map loaded.\n");
3417 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3418 strlcat (name, ".rtlights", sizeof (name));
3419 bufchars = bufmaxchars = 0;
3421 for (light = r_shadow_worldlightchain;light;light = light->next)
3423 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3424 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3425 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3426 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3428 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
3429 if (bufchars + (int) strlen(line) > bufmaxchars)
3431 bufmaxchars = bufchars + strlen(line) + 2048;
3433 buf = Mem_Alloc(tempmempool, bufmaxchars);
3437 memcpy(buf, oldbuf, bufchars);
3443 memcpy(buf + bufchars, line, strlen(line));
3444 bufchars += strlen(line);
3448 FS_WriteFile(name, buf, bufchars);
3453 void R_Shadow_LoadLightsFile(void)
3456 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3457 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3458 if (r_refdef.worldmodel == NULL)
3460 Con_Print("No map loaded.\n");
3463 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3464 strlcat (name, ".lights", sizeof (name));
3465 lightsstring = FS_LoadFile(name, tempmempool, false);
3473 while (*s && *s != '\n' && *s != '\r')
3479 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);
3483 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);
3486 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3487 radius = bound(15, radius, 4096);
3488 VectorScale(color, (2.0f / (8388608.0f)), color);
3489 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3497 Con_Printf("invalid lights file \"%s\"\n", name);
3498 Mem_Free(lightsstring);
3502 // tyrlite/hmap2 light types in the delay field
3503 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3505 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3507 int entnum, style, islight, skin, pflags, effects, type, n;
3510 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3511 char key[256], value[1024];
3513 if (r_refdef.worldmodel == NULL)
3515 Con_Print("No map loaded.\n");
3518 // try to load a .ent file first
3519 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3520 strlcat (key, ".ent", sizeof (key));
3521 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3522 // and if that is not found, fall back to the bsp file entity string
3524 data = r_refdef.worldmodel->brush.entities;
3527 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3529 type = LIGHTTYPE_MINUSX;
3530 origin[0] = origin[1] = origin[2] = 0;
3531 originhack[0] = originhack[1] = originhack[2] = 0;
3532 angles[0] = angles[1] = angles[2] = 0;
3533 color[0] = color[1] = color[2] = 1;
3534 light[0] = light[1] = light[2] = 1;light[3] = 300;
3535 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3545 if (!COM_ParseToken(&data, false))
3547 if (com_token[0] == '}')
3548 break; // end of entity
3549 if (com_token[0] == '_')
3550 strcpy(key, com_token + 1);
3552 strcpy(key, com_token);
3553 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3554 key[strlen(key)-1] = 0;
3555 if (!COM_ParseToken(&data, false))
3557 strcpy(value, com_token);
3559 // now that we have the key pair worked out...
3560 if (!strcmp("light", key))
3562 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3566 light[0] = vec[0] * (1.0f / 256.0f);
3567 light[1] = vec[0] * (1.0f / 256.0f);
3568 light[2] = vec[0] * (1.0f / 256.0f);
3574 light[0] = vec[0] * (1.0f / 255.0f);
3575 light[1] = vec[1] * (1.0f / 255.0f);
3576 light[2] = vec[2] * (1.0f / 255.0f);
3580 else if (!strcmp("delay", key))
3582 else if (!strcmp("origin", key))
3583 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3584 else if (!strcmp("angle", key))
3585 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3586 else if (!strcmp("angles", key))
3587 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3588 else if (!strcmp("color", key))
3589 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3590 else if (!strcmp("wait", key))
3591 fadescale = atof(value);
3592 else if (!strcmp("classname", key))
3594 if (!strncmp(value, "light", 5))
3597 if (!strcmp(value, "light_fluoro"))
3602 overridecolor[0] = 1;
3603 overridecolor[1] = 1;
3604 overridecolor[2] = 1;
3606 if (!strcmp(value, "light_fluorospark"))
3611 overridecolor[0] = 1;
3612 overridecolor[1] = 1;
3613 overridecolor[2] = 1;
3615 if (!strcmp(value, "light_globe"))
3620 overridecolor[0] = 1;
3621 overridecolor[1] = 0.8;
3622 overridecolor[2] = 0.4;
3624 if (!strcmp(value, "light_flame_large_yellow"))
3629 overridecolor[0] = 1;
3630 overridecolor[1] = 0.5;
3631 overridecolor[2] = 0.1;
3633 if (!strcmp(value, "light_flame_small_yellow"))
3638 overridecolor[0] = 1;
3639 overridecolor[1] = 0.5;
3640 overridecolor[2] = 0.1;
3642 if (!strcmp(value, "light_torch_small_white"))
3647 overridecolor[0] = 1;
3648 overridecolor[1] = 0.5;
3649 overridecolor[2] = 0.1;
3651 if (!strcmp(value, "light_torch_small_walltorch"))
3656 overridecolor[0] = 1;
3657 overridecolor[1] = 0.5;
3658 overridecolor[2] = 0.1;
3662 else if (!strcmp("style", key))
3663 style = atoi(value);
3664 else if (r_refdef.worldmodel->type == mod_brushq3)
3666 if (!strcmp("scale", key))
3667 lightscale = atof(value);
3668 if (!strcmp("fade", key))
3669 fadescale = atof(value);
3671 else if (!strcmp("skin", key))
3672 skin = (int)atof(value);
3673 else if (!strcmp("pflags", key))
3674 pflags = (int)atof(value);
3675 else if (!strcmp("effects", key))
3676 effects = (int)atof(value);
3680 if (lightscale <= 0)
3684 if (color[0] == color[1] && color[0] == color[2])
3686 color[0] *= overridecolor[0];
3687 color[1] *= overridecolor[1];
3688 color[2] *= overridecolor[2];
3690 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3691 color[0] = color[0] * light[0];
3692 color[1] = color[1] * light[1];
3693 color[2] = color[2] * light[2];
3696 case LIGHTTYPE_MINUSX:
3698 case LIGHTTYPE_RECIPX:
3700 VectorScale(color, (1.0f / 16.0f), color);
3702 case LIGHTTYPE_RECIPXX:
3704 VectorScale(color, (1.0f / 16.0f), color);
3707 case LIGHTTYPE_NONE:
3711 case LIGHTTYPE_MINUSXX:
3714 VectorAdd(origin, originhack, origin);
3716 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);
3719 Mem_Free(entfiledata);
3723 void R_Shadow_SetCursorLocationForView(void)
3725 vec_t dist, push, frac;
3726 vec3_t dest, endpos, normal;
3727 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3728 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3731 dist = frac * r_editlights_cursordistance.value;
3732 push = r_editlights_cursorpushback.value;
3736 VectorMA(endpos, push, r_viewforward, endpos);
3737 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3739 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3740 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3741 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3744 void R_Shadow_UpdateWorldLightSelection(void)
3746 if (r_editlights.integer)
3748 R_Shadow_SetCursorLocationForView();
3749 R_Shadow_SelectLightInView();
3750 R_Shadow_DrawLightSprites();
3753 R_Shadow_SelectLight(NULL);
3756 void R_Shadow_EditLights_Clear_f(void)
3758 R_Shadow_ClearWorldLights();
3761 void R_Shadow_EditLights_Reload_f(void)
3763 if (!r_refdef.worldmodel)
3765 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3766 R_Shadow_ClearWorldLights();
3767 R_Shadow_LoadWorldLights();
3768 if (r_shadow_worldlightchain == NULL)
3770 R_Shadow_LoadLightsFile();
3771 if (r_shadow_worldlightchain == NULL)
3772 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3776 void R_Shadow_EditLights_Save_f(void)
3778 if (!r_refdef.worldmodel)
3780 R_Shadow_SaveWorldLights();
3783 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3785 R_Shadow_ClearWorldLights();
3786 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3789 void R_Shadow_EditLights_ImportLightsFile_f(void)
3791 R_Shadow_ClearWorldLights();
3792 R_Shadow_LoadLightsFile();
3795 void R_Shadow_EditLights_Spawn_f(void)
3798 if (!r_editlights.integer)
3800 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3803 if (Cmd_Argc() != 1)
3805 Con_Print("r_editlights_spawn does not take parameters\n");
3808 color[0] = color[1] = color[2] = 1;
3809 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3812 void R_Shadow_EditLights_Edit_f(void)
3814 vec3_t origin, angles, color;
3815 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3816 int style, shadows, flags, normalmode, realtimemode;
3817 char cubemapname[1024];
3818 if (!r_editlights.integer)
3820 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3823 if (!r_shadow_selectedlight)
3825 Con_Print("No selected light.\n");
3828 VectorCopy(r_shadow_selectedlight->origin, origin);
3829 VectorCopy(r_shadow_selectedlight->angles, angles);
3830 VectorCopy(r_shadow_selectedlight->color, color);
3831 radius = r_shadow_selectedlight->radius;
3832 style = r_shadow_selectedlight->style;
3833 if (r_shadow_selectedlight->cubemapname)
3834 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3837 shadows = r_shadow_selectedlight->shadow;
3838 corona = r_shadow_selectedlight->corona;
3839 coronasizescale = r_shadow_selectedlight->coronasizescale;
3840 ambientscale = r_shadow_selectedlight->ambientscale;
3841 diffusescale = r_shadow_selectedlight->diffusescale;
3842 specularscale = r_shadow_selectedlight->specularscale;
3843 flags = r_shadow_selectedlight->flags;
3844 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3845 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3846 if (!strcmp(Cmd_Argv(1), "origin"))
3848 if (Cmd_Argc() != 5)
3850 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3853 origin[0] = atof(Cmd_Argv(2));
3854 origin[1] = atof(Cmd_Argv(3));
3855 origin[2] = atof(Cmd_Argv(4));
3857 else if (!strcmp(Cmd_Argv(1), "originx"))
3859 if (Cmd_Argc() != 3)
3861 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3864 origin[0] = atof(Cmd_Argv(2));
3866 else if (!strcmp(Cmd_Argv(1), "originy"))
3868 if (Cmd_Argc() != 3)
3870 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3873 origin[1] = atof(Cmd_Argv(2));
3875 else if (!strcmp(Cmd_Argv(1), "originz"))
3877 if (Cmd_Argc() != 3)
3879 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3882 origin[2] = atof(Cmd_Argv(2));
3884 else if (!strcmp(Cmd_Argv(1), "move"))
3886 if (Cmd_Argc() != 5)
3888 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3891 origin[0] += atof(Cmd_Argv(2));
3892 origin[1] += atof(Cmd_Argv(3));
3893 origin[2] += atof(Cmd_Argv(4));
3895 else if (!strcmp(Cmd_Argv(1), "movex"))
3897 if (Cmd_Argc() != 3)
3899 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3902 origin[0] += atof(Cmd_Argv(2));
3904 else if (!strcmp(Cmd_Argv(1), "movey"))
3906 if (Cmd_Argc() != 3)
3908 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3911 origin[1] += atof(Cmd_Argv(2));
3913 else if (!strcmp(Cmd_Argv(1), "movez"))
3915 if (Cmd_Argc() != 3)
3917 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3920 origin[2] += atof(Cmd_Argv(2));
3922 else if (!strcmp(Cmd_Argv(1), "angles"))
3924 if (Cmd_Argc() != 5)
3926 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3929 angles[0] = atof(Cmd_Argv(2));
3930 angles[1] = atof(Cmd_Argv(3));
3931 angles[2] = atof(Cmd_Argv(4));
3933 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3935 if (Cmd_Argc() != 3)
3937 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3940 angles[0] = atof(Cmd_Argv(2));
3942 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3944 if (Cmd_Argc() != 3)
3946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3949 angles[1] = atof(Cmd_Argv(2));
3951 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3953 if (Cmd_Argc() != 3)
3955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3958 angles[2] = atof(Cmd_Argv(2));
3960 else if (!strcmp(Cmd_Argv(1), "color"))
3962 if (Cmd_Argc() != 5)
3964 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3967 color[0] = atof(Cmd_Argv(2));
3968 color[1] = atof(Cmd_Argv(3));
3969 color[2] = atof(Cmd_Argv(4));
3971 else if (!strcmp(Cmd_Argv(1), "radius"))
3973 if (Cmd_Argc() != 3)
3975 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3978 radius = atof(Cmd_Argv(2));
3980 else if (!strcmp(Cmd_Argv(1), "style"))
3982 if (Cmd_Argc() != 3)
3984 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3987 style = atoi(Cmd_Argv(2));
3989 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3993 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3996 if (Cmd_Argc() == 3)
3997 strcpy(cubemapname, Cmd_Argv(2));
4001 else if (!strcmp(Cmd_Argv(1), "shadows"))
4003 if (Cmd_Argc() != 3)
4005 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4008 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4010 else if (!strcmp(Cmd_Argv(1), "corona"))
4012 if (Cmd_Argc() != 3)
4014 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4017 corona = atof(Cmd_Argv(2));
4019 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4021 if (Cmd_Argc() != 3)
4023 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4026 coronasizescale = atof(Cmd_Argv(2));
4028 else if (!strcmp(Cmd_Argv(1), "ambient"))
4030 if (Cmd_Argc() != 3)
4032 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4035 ambientscale = atof(Cmd_Argv(2));
4037 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4039 if (Cmd_Argc() != 3)
4041 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4044 diffusescale = atof(Cmd_Argv(2));
4046 else if (!strcmp(Cmd_Argv(1), "specular"))
4048 if (Cmd_Argc() != 3)
4050 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4053 specularscale = atof(Cmd_Argv(2));
4055 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4057 if (Cmd_Argc() != 3)
4059 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4062 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4064 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4066 if (Cmd_Argc() != 3)
4068 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4071 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4075 Con_Print("usage: r_editlights_edit [property] [value]\n");
4076 Con_Print("Selected light's properties:\n");
4077 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4078 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4079 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4080 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4081 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4082 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4083 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4084 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4085 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4086 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4087 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4088 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4089 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4090 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4093 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4094 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4097 void R_Shadow_EditLights_EditAll_f(void)
4101 if (!r_editlights.integer)
4103 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4107 for (light = r_shadow_worldlightchain;light;light = light->next)
4109 R_Shadow_SelectLight(light);
4110 R_Shadow_EditLights_Edit_f();
4114 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4116 int lightnumber, lightcount;
4120 if (!r_editlights.integer)
4126 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4127 if (light == r_shadow_selectedlight)
4128 lightnumber = lightcount;
4129 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;
4130 if (r_shadow_selectedlight == NULL)
4132 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4133 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;
4134 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;
4135 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;
4136 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4137 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4138 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4139 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;
4140 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4141 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4142 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4143 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4144 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4145 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;
4146 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;
4149 void R_Shadow_EditLights_ToggleShadow_f(void)
4151 if (!r_editlights.integer)
4153 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4156 if (!r_shadow_selectedlight)
4158 Con_Print("No selected light.\n");
4161 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
4164 void R_Shadow_EditLights_ToggleCorona_f(void)
4166 if (!r_editlights.integer)
4168 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4171 if (!r_shadow_selectedlight)
4173 Con_Print("No selected light.\n");
4176 R_Shadow_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);
4179 void R_Shadow_EditLights_Remove_f(void)
4181 if (!r_editlights.integer)
4183 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4186 if (!r_shadow_selectedlight)
4188 Con_Print("No selected light.\n");
4191 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4192 r_shadow_selectedlight = NULL;
4195 void R_Shadow_EditLights_Help_f(void)
4198 "Documentation on r_editlights system:\n"
4200 "r_editlights : enable/disable editing mode\n"
4201 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4202 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4203 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4204 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4205 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4206 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4207 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4209 "r_editlights_help : this help\n"
4210 "r_editlights_clear : remove all lights\n"
4211 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4212 "r_editlights_save : save to .rtlights file\n"
4213 "r_editlights_spawn : create a light with default settings\n"
4214 "r_editlights_edit command : edit selected light - more documentation below\n"
4215 "r_editlights_remove : remove selected light\n"
4216 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4217 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4218 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4220 "origin x y z : set light location\n"
4221 "originx x: set x component of light location\n"
4222 "originy y: set y component of light location\n"
4223 "originz z: set z component of light location\n"
4224 "move x y z : adjust light location\n"
4225 "movex x: adjust x component of light location\n"
4226 "movey y: adjust y component of light location\n"
4227 "movez z: adjust z component of light location\n"
4228 "angles x y z : set light angles\n"
4229 "anglesx x: set x component of light angles\n"
4230 "anglesy y: set y component of light angles\n"
4231 "anglesz z: set z component of light angles\n"
4232 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4233 "radius radius : set radius (size) of light\n"
4234 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4235 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4236 "shadows 1/0 : turn on/off shadows\n"
4237 "corona n : set corona intensity\n"
4238 "coronasize n : set corona size (0-1)\n"
4239 "ambient n : set ambient intensity (0-1)\n"
4240 "diffuse n : set diffuse intensity (0-1)\n"
4241 "specular n : set specular intensity (0-1)\n"
4242 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4243 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4244 "<nothing> : print light properties to console\n"
4248 void R_Shadow_EditLights_CopyInfo_f(void)
4250 if (!r_editlights.integer)
4252 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4255 if (!r_shadow_selectedlight)
4257 Con_Print("No selected light.\n");
4260 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4261 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4262 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4263 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4264 if (r_shadow_selectedlight->cubemapname)
4265 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4267 r_shadow_bufferlight.cubemapname[0] = 0;
4268 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4269 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4270 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4271 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4272 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4273 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4274 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4277 void R_Shadow_EditLights_PasteInfo_f(void)
4279 if (!r_editlights.integer)
4281 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4284 if (!r_shadow_selectedlight)
4286 Con_Print("No selected light.\n");
4289 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);
4292 void R_Shadow_EditLights_Init(void)
4294 Cvar_RegisterVariable(&r_editlights);
4295 Cvar_RegisterVariable(&r_editlights_cursordistance);
4296 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4297 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4298 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4299 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4300 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4301 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4302 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4303 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4304 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4305 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4306 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4307 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4308 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4309 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4310 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4311 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4312 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4313 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4314 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4315 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);