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_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
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_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
160 rtexture_t *r_shadow_blankwhitecubetexture;
161 rtexture_t *r_shadow_blankblacktexture;
163 // lights are reloaded when this changes
164 char r_shadow_mapname[MAX_QPATH];
166 // used only for light filters (cubemaps)
167 rtexturepool_t *r_shadow_filters_texturepool;
169 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
170 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
171 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
172 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
173 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
174 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
175 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
176 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
177 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
178 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
179 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
180 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
181 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
182 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
183 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
184 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
185 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
186 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "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_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
192 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
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_distance", "1024"};
201 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
202 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
203 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "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 = clamp(1.0 - dot(CubeVector, CubeVector), 0.0, 1.0);\n"
353 " colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
356 "#ifdef USEOFFSETMAPPING\n"
357 " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-1, 1);\n"
358 " vec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
359 " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).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 * clamp(dot(surfacenormal, diffusenormal), 0.0, 1.0));\n"
375 "#ifdef USESPECULAR\n"
376 " color += glosstexel * (SpecularScale * pow(clamp(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0, 1.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_blankbumptexture = NULL;
398 r_shadow_blankglosstexture = NULL;
399 r_shadow_blankwhitetexture = NULL;
400 r_shadow_blankwhitecubetexture = NULL;
401 r_shadow_blankblacktexture = NULL;
402 r_shadow_texturepool = NULL;
403 r_shadow_filters_texturepool = NULL;
404 R_Shadow_ValidateCvars();
405 R_Shadow_MakeTextures();
406 maxshadowelements = 0;
407 shadowelements = NULL;
415 shadowmarklist = NULL;
417 r_shadow_buffer_numclusterpvsbytes = 0;
418 r_shadow_buffer_clusterpvs = NULL;
419 r_shadow_buffer_clusterlist = NULL;
420 r_shadow_buffer_numsurfacepvsbytes = 0;
421 r_shadow_buffer_surfacepvs = NULL;
422 r_shadow_buffer_surfacelist = NULL;
423 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
424 r_shadow_program_light[i] = 0;
425 if (gl_support_fragment_shader)
427 char *vertstring, *fragstring;
428 int vertstrings_count;
429 int fragstrings_count;
430 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
431 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
432 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
433 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
434 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
436 vertstrings_count = 0;
437 fragstrings_count = 0;
438 if (i & SHADERPERMUTATION_SPECULAR)
440 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
441 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
443 if (i & SHADERPERMUTATION_FOG)
445 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
446 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
448 if (i & SHADERPERMUTATION_CUBEFILTER)
450 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
451 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
453 if (i & SHADERPERMUTATION_OFFSETMAPPING)
455 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
456 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
458 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
459 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
460 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
461 qglUseProgramObjectARB(r_shadow_program_light[i]);
462 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
463 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
464 if (i & SHADERPERMUTATION_SPECULAR)
466 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
468 if (i & SHADERPERMUTATION_CUBEFILTER)
470 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
472 if (i & SHADERPERMUTATION_FOG)
474 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
477 qglUseProgramObjectARB(0);
479 Mem_Free(fragstring);
481 Mem_Free(vertstring);
485 void r_shadow_shutdown(void)
488 R_Shadow_UncompileWorldLights();
489 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
491 if (r_shadow_program_light[i])
493 GL_Backend_FreeProgram(r_shadow_program_light[i]);
494 r_shadow_program_light[i] = 0;
498 r_shadow_normalcubetexture = NULL;
499 r_shadow_attenuation2dtexture = NULL;
500 r_shadow_attenuation3dtexture = NULL;
501 r_shadow_blankbumptexture = NULL;
502 r_shadow_blankglosstexture = NULL;
503 r_shadow_blankwhitetexture = NULL;
504 r_shadow_blankwhitecubetexture = NULL;
505 r_shadow_blankblacktexture = NULL;
506 R_FreeTexturePool(&r_shadow_texturepool);
507 R_FreeTexturePool(&r_shadow_filters_texturepool);
508 maxshadowelements = 0;
510 Mem_Free(shadowelements);
511 shadowelements = NULL;
514 Mem_Free(vertexupdate);
517 Mem_Free(vertexremap);
523 Mem_Free(shadowmark);
526 Mem_Free(shadowmarklist);
527 shadowmarklist = NULL;
529 r_shadow_buffer_numclusterpvsbytes = 0;
530 if (r_shadow_buffer_clusterpvs)
531 Mem_Free(r_shadow_buffer_clusterpvs);
532 r_shadow_buffer_clusterpvs = NULL;
533 if (r_shadow_buffer_clusterlist)
534 Mem_Free(r_shadow_buffer_clusterlist);
535 r_shadow_buffer_clusterlist = NULL;
536 r_shadow_buffer_numsurfacepvsbytes = 0;
537 if (r_shadow_buffer_surfacepvs)
538 Mem_Free(r_shadow_buffer_surfacepvs);
539 r_shadow_buffer_surfacepvs = NULL;
540 if (r_shadow_buffer_surfacelist)
541 Mem_Free(r_shadow_buffer_surfacelist);
542 r_shadow_buffer_surfacelist = NULL;
545 void r_shadow_newmap(void)
549 void R_Shadow_Help_f(void)
552 "Documentation on r_shadow system:\n"
554 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
555 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
556 "r_shadow_debuglight : render only this light number (-1 = all)\n"
557 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
558 "r_shadow_gloss2intensity : brightness of forced gloss\n"
559 "r_shadow_glossintensity : brightness of textured gloss\n"
560 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
561 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
562 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
563 "r_shadow_portallight : use portal visibility for static light precomputation\n"
564 "r_shadow_projectdistance : shadow volume projection distance\n"
565 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
566 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
567 "r_shadow_realtime_world : use high quality world lighting mode\n"
568 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
569 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
570 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
571 "r_shadow_glsl : use OpenGL Shading Language for lighting\n"
572 "r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
573 "r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
574 "r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
575 "r_shadow_scissor : use scissor optimization\n"
576 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
577 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
578 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
579 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
580 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
582 "r_shadow_help : this help\n"
586 void R_Shadow_Init(void)
588 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
589 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
590 Cvar_RegisterVariable(&r_shadow_cull);
591 Cvar_RegisterVariable(&r_shadow_debuglight);
592 Cvar_RegisterVariable(&r_shadow_gloss);
593 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
594 Cvar_RegisterVariable(&r_shadow_glossintensity);
595 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
596 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
597 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
598 Cvar_RegisterVariable(&r_shadow_portallight);
599 Cvar_RegisterVariable(&r_shadow_projectdistance);
600 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
601 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
602 Cvar_RegisterVariable(&r_shadow_realtime_world);
603 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
604 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
605 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
606 Cvar_RegisterVariable(&r_shadow_scissor);
607 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
608 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
609 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
610 Cvar_RegisterVariable(&r_shadow_staticworldlights);
611 Cvar_RegisterVariable(&r_shadow_texture3d);
612 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
613 Cvar_RegisterVariable(&r_shadow_glsl);
614 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
615 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
616 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
617 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
618 if (gamemode == GAME_TENEBRAE)
620 Cvar_SetValue("r_shadow_gloss", 2);
621 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
623 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
624 R_Shadow_EditLights_Init();
625 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
626 r_shadow_worldlightchain = NULL;
627 maxshadowelements = 0;
628 shadowelements = NULL;
636 shadowmarklist = NULL;
638 r_shadow_buffer_numclusterpvsbytes = 0;
639 r_shadow_buffer_clusterpvs = NULL;
640 r_shadow_buffer_clusterlist = NULL;
641 r_shadow_buffer_numsurfacepvsbytes = 0;
642 r_shadow_buffer_surfacepvs = NULL;
643 r_shadow_buffer_surfacelist = NULL;
644 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
647 matrix4x4_t matrix_attenuationxyz =
650 {0.5, 0.0, 0.0, 0.5},
651 {0.0, 0.5, 0.0, 0.5},
652 {0.0, 0.0, 0.5, 0.5},
657 matrix4x4_t matrix_attenuationz =
660 {0.0, 0.0, 0.5, 0.5},
661 {0.0, 0.0, 0.0, 0.5},
662 {0.0, 0.0, 0.0, 0.5},
667 int *R_Shadow_ResizeShadowElements(int numtris)
669 // make sure shadowelements is big enough for this volume
670 if (maxshadowelements < numtris * 24)
672 maxshadowelements = numtris * 24;
674 Mem_Free(shadowelements);
675 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
677 return shadowelements;
680 void R_Shadow_EnlargeClusterBuffer(int numclusters)
682 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
683 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
685 if (r_shadow_buffer_clusterpvs)
686 Mem_Free(r_shadow_buffer_clusterpvs);
687 if (r_shadow_buffer_clusterlist)
688 Mem_Free(r_shadow_buffer_clusterlist);
689 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
690 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
691 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
695 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
697 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
698 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
700 if (r_shadow_buffer_surfacepvs)
701 Mem_Free(r_shadow_buffer_surfacepvs);
702 if (r_shadow_buffer_surfacelist)
703 Mem_Free(r_shadow_buffer_surfacelist);
704 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
705 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
706 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
710 void R_Shadow_PrepareShadowMark(int numtris)
712 // make sure shadowmark is big enough for this volume
713 if (maxshadowmark < numtris)
715 maxshadowmark = numtris;
717 Mem_Free(shadowmark);
719 Mem_Free(shadowmarklist);
720 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
721 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
725 // if shadowmarkcount wrapped we clear the array and adjust accordingly
726 if (shadowmarkcount == 0)
729 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
734 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)
736 int i, j, tris = 0, vr[3], t, outvertices = 0;
741 if (maxvertexupdate < innumvertices)
743 maxvertexupdate = innumvertices;
745 Mem_Free(vertexupdate);
747 Mem_Free(vertexremap);
748 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
749 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
753 if (vertexupdatenum == 0)
756 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
757 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
760 for (i = 0;i < numshadowmarktris;i++)
761 shadowmark[shadowmarktris[i]] = shadowmarkcount;
763 for (i = 0;i < numshadowmarktris;i++)
765 t = shadowmarktris[i];
766 e = inelement3i + t * 3;
767 // make sure the vertices are created
768 for (j = 0;j < 3;j++)
770 if (vertexupdate[e[j]] != vertexupdatenum)
772 vertexupdate[e[j]] = vertexupdatenum;
773 vertexremap[e[j]] = outvertices;
774 v = invertex3f + e[j] * 3;
775 // project one copy of the vertex to the sphere radius of the light
776 // (FIXME: would projecting it to the light box be better?)
777 VectorSubtract(v, projectorigin, temp);
778 f = projectdistance / VectorLength(temp);
779 VectorCopy(v, outvertex3f);
780 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
787 for (i = 0;i < numshadowmarktris;i++)
789 t = shadowmarktris[i];
790 e = inelement3i + t * 3;
791 n = inneighbor3i + t * 3;
792 // output the front and back triangles
793 outelement3i[0] = vertexremap[e[0]];
794 outelement3i[1] = vertexremap[e[1]];
795 outelement3i[2] = vertexremap[e[2]];
796 outelement3i[3] = vertexremap[e[2]] + 1;
797 outelement3i[4] = vertexremap[e[1]] + 1;
798 outelement3i[5] = vertexremap[e[0]] + 1;
801 // output the sides (facing outward from this triangle)
802 if (shadowmark[n[0]] != shadowmarkcount)
804 vr[0] = vertexremap[e[0]];
805 vr[1] = vertexremap[e[1]];
806 outelement3i[0] = vr[1];
807 outelement3i[1] = vr[0];
808 outelement3i[2] = vr[0] + 1;
809 outelement3i[3] = vr[1];
810 outelement3i[4] = vr[0] + 1;
811 outelement3i[5] = vr[1] + 1;
815 if (shadowmark[n[1]] != shadowmarkcount)
817 vr[1] = vertexremap[e[1]];
818 vr[2] = vertexremap[e[2]];
819 outelement3i[0] = vr[2];
820 outelement3i[1] = vr[1];
821 outelement3i[2] = vr[1] + 1;
822 outelement3i[3] = vr[2];
823 outelement3i[4] = vr[1] + 1;
824 outelement3i[5] = vr[2] + 1;
828 if (shadowmark[n[2]] != shadowmarkcount)
830 vr[0] = vertexremap[e[0]];
831 vr[2] = vertexremap[e[2]];
832 outelement3i[0] = vr[0];
833 outelement3i[1] = vr[2];
834 outelement3i[2] = vr[2] + 1;
835 outelement3i[3] = vr[0];
836 outelement3i[4] = vr[2] + 1;
837 outelement3i[5] = vr[0] + 1;
843 *outnumvertices = outvertices;
847 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)
850 if (projectdistance < 0.1)
852 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
855 if (!numverts || !nummarktris)
857 // make sure shadowelements is big enough for this volume
858 if (maxshadowelements < nummarktris * 24)
859 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
860 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
861 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
864 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs)
869 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
871 tend = firsttriangle + numtris;
872 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
873 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
874 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
876 // surface box entirely inside light box, no box cull
877 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
878 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
879 shadowmarklist[numshadowmark++] = t;
883 // surface box not entirely inside light box, cull each triangle
884 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
886 v[0] = invertex3f + e[0] * 3;
887 v[1] = invertex3f + e[1] * 3;
888 v[2] = invertex3f + e[2] * 3;
889 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
890 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
891 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
892 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
893 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
894 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
895 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
896 shadowmarklist[numshadowmark++] = t;
901 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
904 if (r_shadow_compilingrtlight)
906 // if we're compiling an rtlight, capture the mesh
907 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
910 memset(&m, 0, sizeof(m));
911 m.pointer_vertex = vertex3f;
913 GL_LockArrays(0, numvertices);
914 if (r_shadowstage == SHADOWSTAGE_STENCIL)
916 // increment stencil if backface is behind depthbuffer
917 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
918 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
919 R_Mesh_Draw(numvertices, numtriangles, element3i);
921 c_rt_shadowtris += numtriangles;
922 // decrement stencil if frontface is behind depthbuffer
923 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
924 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
926 R_Mesh_Draw(numvertices, numtriangles, element3i);
928 c_rt_shadowtris += numtriangles;
932 static void R_Shadow_MakeTextures(void)
934 int x, y, z, d, side;
935 float v[3], s, t, intensity;
937 R_FreeTexturePool(&r_shadow_texturepool);
938 r_shadow_texturepool = R_AllocTexturePool();
939 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
940 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
942 #define ATTEN2DSIZE 64
943 #define ATTEN3DSIZE 32
944 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
945 data[0] = 128; // normal X
946 data[1] = 128; // normal Y
947 data[2] = 255; // normal Z
948 data[3] = 128; // height
949 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
954 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
959 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
964 r_shadow_blankblacktexture = R_LoadTexture2D(r_shadow_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
965 r_shadow_blankwhitecubetexture = NULL;
966 r_shadow_normalcubetexture = NULL;
967 if (gl_texturecubemap)
969 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
970 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
971 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
972 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
973 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
974 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
975 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
976 for (side = 0;side < 6;side++)
978 for (y = 0;y < NORMSIZE;y++)
980 for (x = 0;x < NORMSIZE;x++)
982 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
983 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1017 intensity = 127.0f / sqrt(DotProduct(v, v));
1018 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1019 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1020 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1021 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1025 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1027 for (y = 0;y < ATTEN2DSIZE;y++)
1029 for (x = 0;x < ATTEN2DSIZE;x++)
1031 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1032 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1034 intensity = 1.0f - sqrt(DotProduct(v, v));
1036 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1037 d = bound(0, intensity, 255);
1038 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1039 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1040 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1041 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1044 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1045 if (r_shadow_texture3d.integer)
1047 for (z = 0;z < ATTEN3DSIZE;z++)
1049 for (y = 0;y < ATTEN3DSIZE;y++)
1051 for (x = 0;x < ATTEN3DSIZE;x++)
1053 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1054 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1055 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1056 intensity = 1.0f - sqrt(DotProduct(v, v));
1058 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1059 d = bound(0, intensity, 255);
1060 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1061 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1062 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1063 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1067 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1072 void R_Shadow_ValidateCvars(void)
1074 if (r_shadow_texture3d.integer && !gl_texture3d)
1075 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1076 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1077 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1080 void R_Shadow_Stage_Begin(void)
1084 R_Shadow_ValidateCvars();
1086 if (!r_shadow_attenuation2dtexture
1087 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1088 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1089 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1090 R_Shadow_MakeTextures();
1092 memset(&m, 0, sizeof(m));
1093 GL_BlendFunc(GL_ONE, GL_ZERO);
1094 GL_DepthMask(false);
1097 GL_Color(0, 0, 0, 1);
1098 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1099 qglEnable(GL_CULL_FACE);
1100 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1101 r_shadowstage = SHADOWSTAGE_NONE;
1104 void R_Shadow_Stage_ShadowVolumes(void)
1107 memset(&m, 0, sizeof(m));
1109 GL_Color(1, 1, 1, 1);
1110 GL_ColorMask(0, 0, 0, 0);
1111 GL_BlendFunc(GL_ONE, GL_ZERO);
1112 GL_DepthMask(false);
1114 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1115 //if (r_shadow_shadow_polygonoffset.value != 0)
1117 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1118 // qglEnable(GL_POLYGON_OFFSET_FILL);
1121 // qglDisable(GL_POLYGON_OFFSET_FILL);
1122 qglDepthFunc(GL_LESS);
1123 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1124 qglEnable(GL_STENCIL_TEST);
1125 qglStencilFunc(GL_ALWAYS, 128, ~0);
1126 if (gl_ext_stenciltwoside.integer)
1128 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1129 qglDisable(GL_CULL_FACE);
1130 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1131 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1133 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1134 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1136 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1140 r_shadowstage = SHADOWSTAGE_STENCIL;
1141 qglEnable(GL_CULL_FACE);
1143 // this is changed by every shadow render so its value here is unimportant
1144 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1146 GL_Clear(GL_STENCIL_BUFFER_BIT);
1148 // LordHavoc note: many shadow volumes reside entirely inside the world
1149 // (that is to say they are entirely bounded by their lit surfaces),
1150 // which can be optimized by handling things as an inverted light volume,
1151 // with the shadow boundaries of the world being simulated by an altered
1152 // (129) bias to stencil clearing on such lights
1153 // FIXME: generate inverted light volumes for use as shadow volumes and
1154 // optimize for them as noted above
1157 void R_Shadow_Stage_Light(int shadowtest)
1160 memset(&m, 0, sizeof(m));
1162 GL_BlendFunc(GL_ONE, GL_ONE);
1163 GL_DepthMask(false);
1165 qglPolygonOffset(0, 0);
1166 //qglDisable(GL_POLYGON_OFFSET_FILL);
1167 GL_Color(1, 1, 1, 1);
1168 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1169 qglDepthFunc(GL_EQUAL);
1170 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1171 qglEnable(GL_CULL_FACE);
1173 qglEnable(GL_STENCIL_TEST);
1175 qglDisable(GL_STENCIL_TEST);
1176 if (gl_support_stenciltwoside)
1177 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1179 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1180 // only draw light where this geometry was already rendered AND the
1181 // stencil is 128 (values other than this mean shadow)
1182 qglStencilFunc(GL_EQUAL, 128, ~0);
1183 r_shadowstage = SHADOWSTAGE_LIGHT;
1187 void R_Shadow_Stage_End(void)
1190 memset(&m, 0, sizeof(m));
1192 GL_BlendFunc(GL_ONE, GL_ZERO);
1195 qglPolygonOffset(0, 0);
1196 //qglDisable(GL_POLYGON_OFFSET_FILL);
1197 GL_Color(1, 1, 1, 1);
1198 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1199 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1200 qglDepthFunc(GL_LEQUAL);
1201 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1202 qglDisable(GL_STENCIL_TEST);
1203 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1204 if (gl_support_stenciltwoside)
1205 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1207 qglStencilFunc(GL_ALWAYS, 128, ~0);
1208 r_shadowstage = SHADOWSTAGE_NONE;
1211 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1213 int i, ix1, iy1, ix2, iy2;
1214 float x1, y1, x2, y2, x, y, f;
1215 vec3_t smins, smaxs;
1217 if (!r_shadow_scissor.integer)
1219 // if view is inside the box, just say yes it's visible
1220 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1222 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1225 for (i = 0;i < 3;i++)
1227 if (r_viewforward[i] >= 0)
1238 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1239 if (DotProduct(r_viewforward, v2) <= f)
1241 // entirely behind nearclip plane
1244 if (DotProduct(r_viewforward, v) >= f)
1246 // entirely infront of nearclip plane
1247 x1 = y1 = x2 = y2 = 0;
1248 for (i = 0;i < 8;i++)
1250 v[0] = (i & 1) ? mins[0] : maxs[0];
1251 v[1] = (i & 2) ? mins[1] : maxs[1];
1252 v[2] = (i & 4) ? mins[2] : maxs[2];
1254 GL_TransformToScreen(v, v2);
1255 //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]);
1274 // clipped by nearclip plane
1275 // this is nasty and crude...
1276 // create viewspace bbox
1277 for (i = 0;i < 8;i++)
1279 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1280 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1281 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1282 v2[0] = -DotProduct(v, r_viewleft);
1283 v2[1] = DotProduct(v, r_viewup);
1284 v2[2] = DotProduct(v, r_viewforward);
1287 if (smins[0] > v2[0]) smins[0] = v2[0];
1288 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1289 if (smins[1] > v2[1]) smins[1] = v2[1];
1290 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1291 if (smins[2] > v2[2]) smins[2] = v2[2];
1292 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1296 smins[0] = smaxs[0] = v2[0];
1297 smins[1] = smaxs[1] = v2[1];
1298 smins[2] = smaxs[2] = v2[2];
1301 // now we have a bbox in viewspace
1302 // clip it to the view plane
1305 // return true if that culled the box
1306 if (smins[2] >= smaxs[2])
1308 // ok some of it is infront of the view, transform each corner back to
1309 // worldspace and then to screenspace and make screen rect
1310 // initialize these variables just to avoid compiler warnings
1311 x1 = y1 = x2 = y2 = 0;
1312 for (i = 0;i < 8;i++)
1314 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1315 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1316 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1317 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1318 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1319 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1321 GL_TransformToScreen(v, v2);
1322 //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]);
1339 // this code doesn't handle boxes with any points behind view properly
1340 x1 = 1000;x2 = -1000;
1341 y1 = 1000;y2 = -1000;
1342 for (i = 0;i < 8;i++)
1344 v[0] = (i & 1) ? mins[0] : maxs[0];
1345 v[1] = (i & 2) ? mins[1] : maxs[1];
1346 v[2] = (i & 4) ? mins[2] : maxs[2];
1348 GL_TransformToScreen(v, v2);
1349 //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]);
1367 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1368 if (ix1 < r_view_x) ix1 = r_view_x;
1369 if (iy1 < r_view_y) iy1 = r_view_y;
1370 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1371 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1372 if (ix2 <= ix1 || iy2 <= iy1)
1374 // set up the scissor rectangle
1375 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1376 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1377 //qglEnable(GL_SCISSOR_TEST);
1382 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1384 float *color4f = varray_color4f;
1385 float dist, dot, intensity, v[3], n[3];
1386 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1388 Matrix4x4_Transform(m, vertex3f, v);
1389 if ((dist = DotProduct(v, v)) < 1)
1391 Matrix4x4_Transform3x3(m, normal3f, n);
1392 if ((dot = DotProduct(n, v)) > 0)
1395 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1396 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1397 VectorScale(lightcolor, intensity, color4f);
1402 VectorClear(color4f);
1408 VectorClear(color4f);
1414 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1416 float *color4f = varray_color4f;
1417 float dist, dot, intensity, v[3], n[3];
1418 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1420 Matrix4x4_Transform(m, vertex3f, v);
1421 if ((dist = fabs(v[2])) < 1)
1423 Matrix4x4_Transform3x3(m, normal3f, n);
1424 if ((dot = DotProduct(n, v)) > 0)
1426 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1427 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1428 VectorScale(lightcolor, intensity, color4f);
1433 VectorClear(color4f);
1439 VectorClear(color4f);
1445 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1447 float *color4f = varray_color4f;
1448 float dot, intensity, v[3], n[3];
1449 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1451 Matrix4x4_Transform(m, vertex3f, v);
1452 Matrix4x4_Transform3x3(m, normal3f, n);
1453 if ((dot = DotProduct(n, v)) > 0)
1455 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1456 VectorScale(lightcolor, intensity, color4f);
1461 VectorClear(color4f);
1467 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1469 float *color4f = varray_color4f;
1470 float dist, intensity, v[3];
1471 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1473 Matrix4x4_Transform(m, vertex3f, v);
1474 if ((dist = DotProduct(v, v)) < 1)
1477 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1478 VectorScale(lightcolor, intensity, color4f);
1483 VectorClear(color4f);
1489 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1491 float *color4f = varray_color4f;
1492 float dist, intensity, v[3];
1493 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1495 Matrix4x4_Transform(m, vertex3f, v);
1496 if ((dist = fabs(v[2])) < 1)
1498 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1499 VectorScale(lightcolor, intensity, color4f);
1504 VectorClear(color4f);
1510 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1511 #define USETEXMATRIX
1513 #ifndef USETEXMATRIX
1514 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1515 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1516 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1520 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1521 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1522 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1529 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1533 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1534 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1542 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)
1546 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1548 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1549 // the cubemap normalizes this for us
1550 out3f[0] = DotProduct(svector3f, lightdir);
1551 out3f[1] = DotProduct(tvector3f, lightdir);
1552 out3f[2] = DotProduct(normal3f, lightdir);
1556 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)
1559 float lightdir[3], eyedir[3], halfdir[3];
1560 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1562 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1563 VectorNormalizeFast(lightdir);
1564 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1565 VectorNormalizeFast(eyedir);
1566 VectorAdd(lightdir, eyedir, halfdir);
1567 // the cubemap normalizes this for us
1568 out3f[0] = DotProduct(svector3f, halfdir);
1569 out3f[1] = DotProduct(tvector3f, halfdir);
1570 out3f[2] = DotProduct(normal3f, halfdir);
1574 void R_Shadow_RenderLighting(int numverts, 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 *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
1577 float color[3], color2[3], colorscale;
1579 // FIXME: support EF_NODEPTHTEST
1580 GL_DepthMask(false);
1583 bumptexture = r_shadow_blankbumptexture;
1584 specularscale *= r_shadow_glossintensity.value;
1587 if (r_shadow_gloss.integer >= 2)
1589 glosstexture = r_shadow_blankglosstexture;
1590 specularscale *= r_shadow_gloss2intensity.value;
1594 glosstexture = r_shadow_blankblacktexture;
1598 if (r_shadow_gloss.integer < 1)
1601 lightcubemap = r_shadow_blankwhitecubetexture;
1602 if (ambientscale + diffusescale + specularscale < 0.01)
1604 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1606 unsigned int perm, prog;
1607 // GLSL shader path (GFFX5200, Radeon 9500)
1608 memset(&m, 0, sizeof(m));
1609 m.pointer_vertex = vertex3f;
1610 m.pointer_texcoord[0] = texcoord2f;
1611 m.pointer_texcoord3f[1] = svector3f;
1612 m.pointer_texcoord3f[2] = tvector3f;
1613 m.pointer_texcoord3f[3] = normal3f;
1614 m.tex[0] = R_GetTexture(bumptexture);
1615 m.tex[1] = R_GetTexture(basetexture);
1616 m.tex[2] = R_GetTexture(glosstexture);
1617 m.texcubemap[3] = R_GetTexture(lightcubemap);
1618 // TODO: support fog (after renderer is converted to texture fog)
1619 m.tex[4] = R_GetTexture(r_shadow_blankwhitetexture);
1620 m.texmatrix[3] = *matrix_modeltolight;
1622 GL_BlendFunc(GL_ONE, GL_ONE);
1623 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1627 perm |= SHADERPERMUTATION_SPECULAR;
1629 // perm |= SHADERPERMUTATION_FOG;
1631 perm |= SHADERPERMUTATION_CUBEFILTER;
1632 if (r_shadow_glsl_offsetmapping.integer)
1633 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1634 prog = r_shadow_program_light[perm];
1635 qglUseProgramObjectARB(r_shadow_program_light[perm]);CHECKGLERROR
1636 // TODO: support fog (after renderer is converted to texture fog)
1637 if (perm & SHADERPERMUTATION_FOG)
1639 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
1641 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
1642 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
1643 if (perm & SHADERPERMUTATION_SPECULAR)
1645 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
1646 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
1648 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);CHECKGLERROR
1649 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
1650 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1652 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
1654 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1656 // these are * 0.25 because the offsetmapping shader does the process 4 times
1657 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value * 0.25);CHECKGLERROR
1658 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value * 0.25);CHECKGLERROR
1661 GL_LockArrays(0, numverts);
1662 R_Mesh_Draw(numverts, numtriangles, elements);
1664 c_rt_lighttris += numtriangles;
1665 GL_LockArrays(0, 0);
1666 qglUseProgramObjectARB(0);
1667 // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
1668 qglBegin(GL_TRIANGLES);
1672 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1675 bumptexture = r_shadow_blankbumptexture;
1677 glosstexture = r_shadow_blankglosstexture;
1681 colorscale = ambientscale;
1682 // colorscale accounts for how much we multiply the brightness
1685 // mult is how many times the final pass of the lighting will be
1686 // performed to get more brightness than otherwise possible.
1688 // Limit mult to 64 for sanity sake.
1689 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1691 // 3 3D combine path (Geforce3, Radeon 8500)
1692 memset(&m, 0, sizeof(m));
1693 m.pointer_vertex = vertex3f;
1694 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1696 m.pointer_texcoord3f[0] = vertex3f;
1697 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1699 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1700 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1702 m.tex[1] = R_GetTexture(basetexture);
1703 m.pointer_texcoord[1] = texcoord2f;
1704 m.texcubemap[2] = R_GetTexture(lightcubemap);
1706 m.pointer_texcoord3f[2] = vertex3f;
1707 m.texmatrix[2] = *matrix_modeltolight;
1709 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1710 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1712 GL_BlendFunc(GL_ONE, GL_ONE);
1714 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1716 // 2 3D combine path (Geforce3, original Radeon)
1717 memset(&m, 0, sizeof(m));
1718 m.pointer_vertex = vertex3f;
1719 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1721 m.pointer_texcoord3f[0] = vertex3f;
1722 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1724 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1725 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1727 m.tex[1] = R_GetTexture(basetexture);
1728 m.pointer_texcoord[1] = texcoord2f;
1729 GL_BlendFunc(GL_ONE, GL_ONE);
1731 else if (r_textureunits.integer >= 4 && lightcubemap)
1733 // 4 2D combine path (Geforce3, Radeon 8500)
1734 memset(&m, 0, sizeof(m));
1735 m.pointer_vertex = vertex3f;
1736 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1738 m.pointer_texcoord3f[0] = vertex3f;
1739 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1741 m.pointer_texcoord[0] = varray_texcoord2f[0];
1742 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1744 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1746 m.pointer_texcoord3f[1] = vertex3f;
1747 m.texmatrix[1] = *matrix_modeltoattenuationz;
1749 m.pointer_texcoord[1] = varray_texcoord2f[1];
1750 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1752 m.tex[2] = R_GetTexture(basetexture);
1753 m.pointer_texcoord[2] = texcoord2f;
1756 m.texcubemap[3] = R_GetTexture(lightcubemap);
1758 m.pointer_texcoord3f[3] = vertex3f;
1759 m.texmatrix[3] = *matrix_modeltolight;
1761 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1762 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1765 GL_BlendFunc(GL_ONE, GL_ONE);
1767 else if (r_textureunits.integer >= 3 && !lightcubemap)
1769 // 3 2D combine path (Geforce3, original Radeon)
1770 memset(&m, 0, sizeof(m));
1771 m.pointer_vertex = vertex3f;
1772 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1774 m.pointer_texcoord3f[0] = vertex3f;
1775 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1777 m.pointer_texcoord[0] = varray_texcoord2f[0];
1778 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1780 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1782 m.pointer_texcoord3f[1] = vertex3f;
1783 m.texmatrix[1] = *matrix_modeltoattenuationz;
1785 m.pointer_texcoord[1] = varray_texcoord2f[1];
1786 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1788 m.tex[2] = R_GetTexture(basetexture);
1789 m.pointer_texcoord[2] = texcoord2f;
1790 GL_BlendFunc(GL_ONE, GL_ONE);
1794 // 2/2/2 2D combine path (any dot3 card)
1795 memset(&m, 0, sizeof(m));
1796 m.pointer_vertex = vertex3f;
1797 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1799 m.pointer_texcoord3f[0] = vertex3f;
1800 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1802 m.pointer_texcoord[0] = varray_texcoord2f[0];
1803 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1805 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1807 m.pointer_texcoord3f[1] = vertex3f;
1808 m.texmatrix[1] = *matrix_modeltoattenuationz;
1810 m.pointer_texcoord[1] = varray_texcoord2f[1];
1811 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1814 GL_ColorMask(0,0,0,1);
1815 GL_BlendFunc(GL_ONE, GL_ZERO);
1816 GL_LockArrays(0, numverts);
1817 R_Mesh_Draw(numverts, numtriangles, elements);
1818 GL_LockArrays(0, 0);
1820 c_rt_lighttris += numtriangles;
1822 memset(&m, 0, sizeof(m));
1823 m.pointer_vertex = vertex3f;
1824 m.tex[0] = R_GetTexture(basetexture);
1825 m.pointer_texcoord[0] = texcoord2f;
1828 m.texcubemap[1] = R_GetTexture(lightcubemap);
1830 m.pointer_texcoord3f[1] = vertex3f;
1831 m.texmatrix[1] = *matrix_modeltolight;
1833 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1834 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1837 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1839 // this final code is shared
1841 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1842 VectorScale(lightcolor, colorscale, color2);
1843 GL_LockArrays(0, numverts);
1844 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1846 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1847 R_Mesh_Draw(numverts, numtriangles, elements);
1849 c_rt_lighttris += numtriangles;
1851 GL_LockArrays(0, 0);
1856 colorscale = diffusescale;
1857 // colorscale accounts for how much we multiply the brightness
1860 // mult is how many times the final pass of the lighting will be
1861 // performed to get more brightness than otherwise possible.
1863 // Limit mult to 64 for sanity sake.
1864 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1866 // 3/2 3D combine path (Geforce3, Radeon 8500)
1867 memset(&m, 0, sizeof(m));
1868 m.pointer_vertex = vertex3f;
1869 m.tex[0] = R_GetTexture(bumptexture);
1870 m.texcombinergb[0] = GL_REPLACE;
1871 m.pointer_texcoord[0] = texcoord2f;
1872 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1873 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1874 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1875 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1876 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1878 m.pointer_texcoord3f[2] = vertex3f;
1879 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1881 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1882 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1885 GL_ColorMask(0,0,0,1);
1886 GL_BlendFunc(GL_ONE, GL_ZERO);
1887 GL_LockArrays(0, numverts);
1888 R_Mesh_Draw(numverts, numtriangles, elements);
1889 GL_LockArrays(0, 0);
1891 c_rt_lighttris += numtriangles;
1893 memset(&m, 0, sizeof(m));
1894 m.pointer_vertex = vertex3f;
1895 m.tex[0] = R_GetTexture(basetexture);
1896 m.pointer_texcoord[0] = texcoord2f;
1899 m.texcubemap[1] = R_GetTexture(lightcubemap);
1901 m.pointer_texcoord3f[1] = vertex3f;
1902 m.texmatrix[1] = *matrix_modeltolight;
1904 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1905 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1908 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1910 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1912 // 1/2/2 3D combine path (original Radeon)
1913 memset(&m, 0, sizeof(m));
1914 m.pointer_vertex = vertex3f;
1915 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1917 m.pointer_texcoord3f[0] = vertex3f;
1918 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1920 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1921 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1924 GL_ColorMask(0,0,0,1);
1925 GL_BlendFunc(GL_ONE, GL_ZERO);
1926 GL_LockArrays(0, numverts);
1927 R_Mesh_Draw(numverts, numtriangles, elements);
1928 GL_LockArrays(0, 0);
1930 c_rt_lighttris += numtriangles;
1932 memset(&m, 0, sizeof(m));
1933 m.pointer_vertex = vertex3f;
1934 m.tex[0] = R_GetTexture(bumptexture);
1935 m.texcombinergb[0] = GL_REPLACE;
1936 m.pointer_texcoord[0] = texcoord2f;
1937 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1938 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1939 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1940 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1942 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1943 GL_LockArrays(0, numverts);
1944 R_Mesh_Draw(numverts, numtriangles, elements);
1945 GL_LockArrays(0, 0);
1947 c_rt_lighttris += numtriangles;
1949 memset(&m, 0, sizeof(m));
1950 m.pointer_vertex = vertex3f;
1951 m.tex[0] = R_GetTexture(basetexture);
1952 m.pointer_texcoord[0] = texcoord2f;
1955 m.texcubemap[1] = R_GetTexture(lightcubemap);
1957 m.pointer_texcoord3f[1] = vertex3f;
1958 m.texmatrix[1] = *matrix_modeltolight;
1960 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1961 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1964 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1966 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1968 // 2/2 3D combine path (original Radeon)
1969 memset(&m, 0, sizeof(m));
1970 m.pointer_vertex = vertex3f;
1971 m.tex[0] = R_GetTexture(bumptexture);
1972 m.texcombinergb[0] = GL_REPLACE;
1973 m.pointer_texcoord[0] = texcoord2f;
1974 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1975 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1976 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1977 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1979 GL_ColorMask(0,0,0,1);
1980 GL_BlendFunc(GL_ONE, GL_ZERO);
1981 GL_LockArrays(0, numverts);
1982 R_Mesh_Draw(numverts, numtriangles, elements);
1983 GL_LockArrays(0, 0);
1985 c_rt_lighttris += numtriangles;
1987 memset(&m, 0, sizeof(m));
1988 m.pointer_vertex = vertex3f;
1989 m.tex[0] = R_GetTexture(basetexture);
1990 m.pointer_texcoord[0] = texcoord2f;
1991 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1993 m.pointer_texcoord3f[1] = vertex3f;
1994 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1996 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1997 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1999 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2001 else if (r_textureunits.integer >= 4)
2003 // 4/2 2D combine path (Geforce3, Radeon 8500)
2004 memset(&m, 0, sizeof(m));
2005 m.pointer_vertex = vertex3f;
2006 m.tex[0] = R_GetTexture(bumptexture);
2007 m.texcombinergb[0] = GL_REPLACE;
2008 m.pointer_texcoord[0] = texcoord2f;
2009 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2010 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2011 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2012 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2013 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2015 m.pointer_texcoord3f[2] = vertex3f;
2016 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2018 m.pointer_texcoord[2] = varray_texcoord2f[2];
2019 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2021 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2023 m.pointer_texcoord3f[3] = vertex3f;
2024 m.texmatrix[3] = *matrix_modeltoattenuationz;
2026 m.pointer_texcoord[3] = varray_texcoord2f[3];
2027 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2030 GL_ColorMask(0,0,0,1);
2031 GL_BlendFunc(GL_ONE, GL_ZERO);
2032 GL_LockArrays(0, numverts);
2033 R_Mesh_Draw(numverts, numtriangles, elements);
2034 GL_LockArrays(0, 0);
2036 c_rt_lighttris += numtriangles;
2038 memset(&m, 0, sizeof(m));
2039 m.pointer_vertex = vertex3f;
2040 m.tex[0] = R_GetTexture(basetexture);
2041 m.pointer_texcoord[0] = texcoord2f;
2044 m.texcubemap[1] = R_GetTexture(lightcubemap);
2046 m.pointer_texcoord3f[1] = vertex3f;
2047 m.texmatrix[1] = *matrix_modeltolight;
2049 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2050 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2053 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2057 // 2/2/2 2D combine path (any dot3 card)
2058 memset(&m, 0, sizeof(m));
2059 m.pointer_vertex = vertex3f;
2060 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2062 m.pointer_texcoord3f[0] = vertex3f;
2063 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2065 m.pointer_texcoord[0] = varray_texcoord2f[0];
2066 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2068 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2070 m.pointer_texcoord3f[1] = vertex3f;
2071 m.texmatrix[1] = *matrix_modeltoattenuationz;
2073 m.pointer_texcoord[1] = varray_texcoord2f[1];
2074 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2077 GL_ColorMask(0,0,0,1);
2078 GL_BlendFunc(GL_ONE, GL_ZERO);
2079 GL_LockArrays(0, numverts);
2080 R_Mesh_Draw(numverts, numtriangles, elements);
2081 GL_LockArrays(0, 0);
2083 c_rt_lighttris += numtriangles;
2085 memset(&m, 0, sizeof(m));
2086 m.pointer_vertex = vertex3f;
2087 m.tex[0] = R_GetTexture(bumptexture);
2088 m.texcombinergb[0] = GL_REPLACE;
2089 m.pointer_texcoord[0] = texcoord2f;
2090 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2091 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2092 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2093 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2095 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2096 GL_LockArrays(0, numverts);
2097 R_Mesh_Draw(numverts, numtriangles, elements);
2098 GL_LockArrays(0, 0);
2100 c_rt_lighttris += numtriangles;
2102 memset(&m, 0, sizeof(m));
2103 m.pointer_vertex = vertex3f;
2104 m.tex[0] = R_GetTexture(basetexture);
2105 m.pointer_texcoord[0] = texcoord2f;
2108 m.texcubemap[1] = R_GetTexture(lightcubemap);
2110 m.pointer_texcoord3f[1] = vertex3f;
2111 m.texmatrix[1] = *matrix_modeltolight;
2113 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2114 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2117 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2119 // this final code is shared
2121 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2122 VectorScale(lightcolor, colorscale, color2);
2123 GL_LockArrays(0, numverts);
2124 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2126 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2127 R_Mesh_Draw(numverts, numtriangles, elements);
2129 c_rt_lighttris += numtriangles;
2131 GL_LockArrays(0, 0);
2133 if (specularscale && glosstexture != r_shadow_blankblacktexture)
2135 // FIXME: detect blendsquare!
2136 //if (gl_support_blendsquare)
2138 colorscale = specularscale;
2140 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2142 // 2/0/0/1/2 3D combine blendsquare path
2143 memset(&m, 0, sizeof(m));
2144 m.pointer_vertex = vertex3f;
2145 m.tex[0] = R_GetTexture(bumptexture);
2146 m.pointer_texcoord[0] = texcoord2f;
2147 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2148 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2149 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2150 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2152 GL_ColorMask(0,0,0,1);
2153 // this squares the result
2154 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2155 GL_LockArrays(0, numverts);
2156 R_Mesh_Draw(numverts, numtriangles, elements);
2157 GL_LockArrays(0, 0);
2159 c_rt_lighttris += numtriangles;
2161 memset(&m, 0, sizeof(m));
2162 m.pointer_vertex = vertex3f;
2164 GL_LockArrays(0, numverts);
2165 // square alpha in framebuffer a few times to make it shiny
2166 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2167 // these comments are a test run through this math for intensity 0.5
2168 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2169 // 0.25 * 0.25 = 0.0625 (this is another pass)
2170 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2171 R_Mesh_Draw(numverts, numtriangles, elements);
2173 c_rt_lighttris += numtriangles;
2174 R_Mesh_Draw(numverts, numtriangles, elements);
2176 c_rt_lighttris += numtriangles;
2177 GL_LockArrays(0, 0);
2179 memset(&m, 0, sizeof(m));
2180 m.pointer_vertex = vertex3f;
2181 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2183 m.pointer_texcoord3f[0] = vertex3f;
2184 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2186 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2187 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2190 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2191 GL_LockArrays(0, numverts);
2192 R_Mesh_Draw(numverts, numtriangles, elements);
2193 GL_LockArrays(0, 0);
2195 c_rt_lighttris += numtriangles;
2197 memset(&m, 0, sizeof(m));
2198 m.pointer_vertex = vertex3f;
2199 m.tex[0] = R_GetTexture(glosstexture);
2200 m.pointer_texcoord[0] = texcoord2f;
2203 m.texcubemap[1] = R_GetTexture(lightcubemap);
2205 m.pointer_texcoord3f[1] = vertex3f;
2206 m.texmatrix[1] = *matrix_modeltolight;
2208 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2209 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2212 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2214 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2216 // 2/0/0/2 3D combine blendsquare path
2217 memset(&m, 0, sizeof(m));
2218 m.pointer_vertex = vertex3f;
2219 m.tex[0] = R_GetTexture(bumptexture);
2220 m.pointer_texcoord[0] = texcoord2f;
2221 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2222 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2223 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2224 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2226 GL_ColorMask(0,0,0,1);
2227 // this squares the result
2228 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2229 GL_LockArrays(0, numverts);
2230 R_Mesh_Draw(numverts, numtriangles, elements);
2231 GL_LockArrays(0, 0);
2233 c_rt_lighttris += numtriangles;
2235 memset(&m, 0, sizeof(m));
2236 m.pointer_vertex = vertex3f;
2238 GL_LockArrays(0, numverts);
2239 // square alpha in framebuffer a few times to make it shiny
2240 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2241 // these comments are a test run through this math for intensity 0.5
2242 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2243 // 0.25 * 0.25 = 0.0625 (this is another pass)
2244 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2245 R_Mesh_Draw(numverts, numtriangles, elements);
2247 c_rt_lighttris += numtriangles;
2248 R_Mesh_Draw(numverts, numtriangles, elements);
2250 c_rt_lighttris += numtriangles;
2251 GL_LockArrays(0, 0);
2253 memset(&m, 0, sizeof(m));
2254 m.pointer_vertex = vertex3f;
2255 m.tex[0] = R_GetTexture(glosstexture);
2256 m.pointer_texcoord[0] = texcoord2f;
2257 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2259 m.pointer_texcoord3f[1] = vertex3f;
2260 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2262 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2263 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2265 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2269 // 2/0/0/2/2 2D combine blendsquare path
2270 memset(&m, 0, sizeof(m));
2271 m.pointer_vertex = vertex3f;
2272 m.tex[0] = R_GetTexture(bumptexture);
2273 m.pointer_texcoord[0] = texcoord2f;
2274 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2275 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2276 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2277 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2279 GL_ColorMask(0,0,0,1);
2280 // this squares the result
2281 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2282 GL_LockArrays(0, numverts);
2283 R_Mesh_Draw(numverts, numtriangles, elements);
2284 GL_LockArrays(0, 0);
2286 c_rt_lighttris += numtriangles;
2288 memset(&m, 0, sizeof(m));
2289 m.pointer_vertex = vertex3f;
2291 GL_LockArrays(0, numverts);
2292 // square alpha in framebuffer a few times to make it shiny
2293 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2294 // these comments are a test run through this math for intensity 0.5
2295 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2296 // 0.25 * 0.25 = 0.0625 (this is another pass)
2297 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2298 R_Mesh_Draw(numverts, numtriangles, elements);
2300 c_rt_lighttris += numtriangles;
2301 R_Mesh_Draw(numverts, numtriangles, elements);
2303 c_rt_lighttris += numtriangles;
2304 GL_LockArrays(0, 0);
2306 memset(&m, 0, sizeof(m));
2307 m.pointer_vertex = vertex3f;
2308 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2310 m.pointer_texcoord3f[0] = vertex3f;
2311 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2313 m.pointer_texcoord[0] = varray_texcoord2f[0];
2314 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2316 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2318 m.pointer_texcoord3f[1] = vertex3f;
2319 m.texmatrix[1] = *matrix_modeltoattenuationz;
2321 m.pointer_texcoord[1] = varray_texcoord2f[1];
2322 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2325 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2326 GL_LockArrays(0, numverts);
2327 R_Mesh_Draw(numverts, numtriangles, elements);
2328 GL_LockArrays(0, 0);
2330 c_rt_lighttris += numtriangles;
2332 memset(&m, 0, sizeof(m));
2333 m.pointer_vertex = vertex3f;
2334 m.tex[0] = R_GetTexture(glosstexture);
2335 m.pointer_texcoord[0] = texcoord2f;
2338 m.texcubemap[1] = R_GetTexture(lightcubemap);
2340 m.pointer_texcoord3f[1] = vertex3f;
2341 m.texmatrix[1] = *matrix_modeltolight;
2343 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2344 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2347 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2350 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2351 VectorScale(lightcolor, colorscale, color2);
2352 GL_LockArrays(0, numverts);
2353 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2355 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2356 R_Mesh_Draw(numverts, numtriangles, elements);
2358 c_rt_lighttris += numtriangles;
2360 GL_LockArrays(0, 0);
2368 GL_BlendFunc(GL_ONE, GL_ONE);
2369 VectorScale(lightcolor, ambientscale, color2);
2370 memset(&m, 0, sizeof(m));
2371 m.pointer_vertex = vertex3f;
2372 m.tex[0] = R_GetTexture(basetexture);
2373 m.pointer_texcoord[0] = texcoord2f;
2374 if (r_textureunits.integer >= 2)
2377 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2379 m.pointer_texcoord3f[1] = vertex3f;
2380 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2382 m.pointer_texcoord[1] = varray_texcoord2f[1];
2383 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2385 if (r_textureunits.integer >= 3)
2387 // Geforce3/Radeon class but not using dot3
2388 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2390 m.pointer_texcoord3f[2] = vertex3f;
2391 m.texmatrix[2] = *matrix_modeltoattenuationz;
2393 m.pointer_texcoord[2] = varray_texcoord2f[2];
2394 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2398 if (r_textureunits.integer >= 3)
2399 m.pointer_color = NULL;
2401 m.pointer_color = varray_color4f;
2403 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2405 color[0] = bound(0, color2[0], 1);
2406 color[1] = bound(0, color2[1], 1);
2407 color[2] = bound(0, color2[2], 1);
2408 if (r_textureunits.integer >= 3)
2409 GL_Color(color[0], color[1], color[2], 1);
2410 else if (r_textureunits.integer >= 2)
2411 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2413 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2414 GL_LockArrays(0, numverts);
2415 R_Mesh_Draw(numverts, numtriangles, elements);
2416 GL_LockArrays(0, 0);
2418 c_rt_lighttris += numtriangles;
2423 GL_BlendFunc(GL_ONE, GL_ONE);
2424 VectorScale(lightcolor, diffusescale, color2);
2425 memset(&m, 0, sizeof(m));
2426 m.pointer_vertex = vertex3f;
2427 m.pointer_color = varray_color4f;
2428 m.tex[0] = R_GetTexture(basetexture);
2429 m.pointer_texcoord[0] = texcoord2f;
2430 if (r_textureunits.integer >= 2)
2433 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2435 m.pointer_texcoord3f[1] = vertex3f;
2436 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2438 m.pointer_texcoord[1] = varray_texcoord2f[1];
2439 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2441 if (r_textureunits.integer >= 3)
2443 // Geforce3/Radeon class but not using dot3
2444 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2446 m.pointer_texcoord3f[2] = vertex3f;
2447 m.texmatrix[2] = *matrix_modeltoattenuationz;
2449 m.pointer_texcoord[2] = varray_texcoord2f[2];
2450 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2455 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2457 color[0] = bound(0, color2[0], 1);
2458 color[1] = bound(0, color2[1], 1);
2459 color[2] = bound(0, color2[2], 1);
2460 if (r_textureunits.integer >= 3)
2461 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2462 else if (r_textureunits.integer >= 2)
2463 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2465 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2466 GL_LockArrays(0, numverts);
2467 R_Mesh_Draw(numverts, numtriangles, elements);
2468 GL_LockArrays(0, 0);
2470 c_rt_lighttris += numtriangles;
2476 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2480 R_RTLight_Uncompile(rtlight);
2481 memset(rtlight, 0, sizeof(*rtlight));
2483 VectorCopy(light->origin, rtlight->shadoworigin);
2484 VectorCopy(light->color, rtlight->color);
2485 rtlight->radius = light->radius;
2486 //rtlight->cullradius = rtlight->radius;
2487 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2488 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2489 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2490 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2491 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2492 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2493 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2494 rtlight->cubemapname[0] = 0;
2495 if (light->cubemapname[0])
2496 strcpy(rtlight->cubemapname, light->cubemapname);
2497 else if (light->cubemapnum > 0)
2498 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2499 rtlight->shadow = light->shadow;
2500 rtlight->corona = light->corona;
2501 rtlight->style = light->style;
2502 rtlight->isstatic = isstatic;
2503 rtlight->coronasizescale = light->coronasizescale;
2504 rtlight->ambientscale = light->ambientscale;
2505 rtlight->diffusescale = light->diffusescale;
2506 rtlight->specularscale = light->specularscale;
2507 rtlight->flags = light->flags;
2508 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2509 // ConcatScale won't work here because this needs to scale rotate and
2510 // translate, not just rotate
2511 scale = 1.0f / rtlight->radius;
2512 for (k = 0;k < 3;k++)
2513 for (j = 0;j < 4;j++)
2514 rtlight->matrix_worldtolight.m[k][j] *= scale;
2515 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2516 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2518 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2519 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2520 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2521 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2524 // compiles rtlight geometry
2525 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2526 void R_RTLight_Compile(rtlight_t *rtlight)
2528 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2529 entity_render_t *ent = &cl_entities[0].render;
2530 model_t *model = ent->model;
2532 // compile the light
2533 rtlight->compiled = true;
2534 rtlight->static_numclusters = 0;
2535 rtlight->static_numclusterpvsbytes = 0;
2536 rtlight->static_clusterlist = NULL;
2537 rtlight->static_clusterpvs = NULL;
2538 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2539 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2540 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2541 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2542 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2543 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2545 if (model && model->GetLightInfo)
2547 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2548 r_shadow_compilingrtlight = rtlight;
2549 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2550 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2551 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2552 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2553 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2556 rtlight->static_numclusters = numclusters;
2557 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2558 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2559 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2561 if (model->DrawShadowVolume && rtlight->shadow)
2563 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2564 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2565 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2567 if (model->DrawLight)
2569 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2570 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);
2571 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2573 // switch back to rendering when DrawShadowVolume or DrawLight is called
2574 r_shadow_compilingrtlight = NULL;
2578 // use smallest available cullradius - box radius or light radius
2579 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2580 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2584 if (rtlight->static_meshchain_shadow)
2587 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2590 shadowtris += mesh->numtriangles;
2596 if (rtlight->static_meshchain_light)
2599 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2602 lighttris += mesh->numtriangles;
2606 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);
2609 void R_RTLight_Uncompile(rtlight_t *rtlight)
2611 if (rtlight->compiled)
2613 if (rtlight->static_meshchain_shadow)
2614 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2615 rtlight->static_meshchain_shadow = NULL;
2616 if (rtlight->static_meshchain_light)
2617 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2618 rtlight->static_meshchain_light = NULL;
2619 if (rtlight->static_clusterlist)
2620 Mem_Free(rtlight->static_clusterlist);
2621 rtlight->static_clusterlist = NULL;
2622 if (rtlight->static_clusterpvs)
2623 Mem_Free(rtlight->static_clusterpvs);
2624 rtlight->static_clusterpvs = NULL;
2625 rtlight->static_numclusters = 0;
2626 rtlight->static_numclusterpvsbytes = 0;
2627 rtlight->compiled = false;
2631 void R_Shadow_UncompileWorldLights(void)
2634 for (light = r_shadow_worldlightchain;light;light = light->next)
2635 R_RTLight_Uncompile(&light->rtlight);
2638 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2640 int i, shadow, usestencil;
2641 entity_render_t *ent;
2643 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2644 rtexture_t *cubemaptexture;
2645 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2646 int numclusters, numsurfaces;
2647 int *clusterlist, *surfacelist;
2649 vec3_t cullmins, cullmaxs;
2653 // skip lights that don't light (corona only lights)
2654 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2657 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2658 VectorScale(rtlight->color, f, lightcolor);
2659 if (VectorLength2(lightcolor) < 0.01)
2662 if (rtlight->selected)
2664 f = 2 + sin(realtime * M_PI * 4.0);
2665 VectorScale(lightcolor, f, lightcolor);
2669 // loading is done before visibility checks because loading should happen
2670 // all at once at the start of a level, not when it stalls gameplay.
2671 // (especially important to benchmarks)
2672 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2673 R_RTLight_Compile(rtlight);
2674 if (rtlight->cubemapname[0])
2675 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2677 cubemaptexture = NULL;
2679 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2680 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2681 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2682 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2683 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2684 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2685 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2692 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2694 // compiled light, world available and can receive realtime lighting
2695 // retrieve cluster information
2696 numclusters = rtlight->static_numclusters;
2697 clusterlist = rtlight->static_clusterlist;
2698 clusterpvs = rtlight->static_clusterpvs;
2699 VectorCopy(rtlight->cullmins, cullmins);
2700 VectorCopy(rtlight->cullmaxs, cullmaxs);
2702 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2704 // dynamic light, world available and can receive realtime lighting
2705 // if the light box is offscreen, skip it right away
2706 if (R_CullBox(cullmins, cullmaxs))
2708 // calculate lit surfaces and clusters
2709 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2710 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2711 r_refdef.worldmodel->GetLightInfo(&cl_entities[0].render, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2712 clusterlist = r_shadow_buffer_clusterlist;
2713 clusterpvs = r_shadow_buffer_clusterpvs;
2714 surfacelist = r_shadow_buffer_surfacelist;
2716 // if the reduced cluster bounds are offscreen, skip it
2717 if (R_CullBox(cullmins, cullmaxs))
2719 // check if light is illuminating any visible clusters
2722 for (i = 0;i < numclusters;i++)
2723 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2725 if (i == numclusters)
2728 // set up a scissor rectangle for this light
2729 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2732 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2735 if (shadow && (gl_stencil || visiblevolumes))
2737 if (!visiblevolumes)
2739 R_Shadow_Stage_ShadowVolumes();
2742 ent = &cl_entities[0].render;
2743 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2745 memset(&m, 0, sizeof(m));
2746 R_Mesh_Matrix(&ent->matrix);
2747 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2749 m.pointer_vertex = mesh->vertex3f;
2751 GL_LockArrays(0, mesh->numverts);
2752 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2754 // increment stencil if backface is behind depthbuffer
2755 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2756 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2757 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2758 c_rtcached_shadowmeshes++;
2759 c_rtcached_shadowtris += mesh->numtriangles;
2760 // decrement stencil if frontface is behind depthbuffer
2761 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2762 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2764 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2765 c_rtcached_shadowmeshes++;
2766 c_rtcached_shadowtris += mesh->numtriangles;
2767 GL_LockArrays(0, 0);
2770 else if (numsurfaces)
2772 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2773 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2775 if (r_drawentities.integer)
2777 for (i = 0;i < r_refdef.numentities;i++)
2779 ent = r_refdef.entities[i];
2781 if (r_shadow_cull.integer)
2783 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2785 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2788 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2790 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2791 // light emitting entities should not cast their own shadow
2792 if (VectorLength2(relativelightorigin) < 0.1)
2794 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2799 if (!visiblevolumes)
2801 R_Shadow_Stage_Light(usestencil);
2803 ent = &cl_entities[0].render;
2804 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2806 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2807 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2808 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2809 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2810 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2811 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2812 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2813 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2814 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2816 R_Mesh_Matrix(&ent->matrix);
2817 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2818 R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
2821 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2823 if (r_drawentities.integer)
2825 for (i = 0;i < r_refdef.numentities;i++)
2827 ent = r_refdef.entities[i];
2828 // can't draw transparent entity lighting here because
2829 // transparent meshes are deferred for later
2830 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)
2832 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2833 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2834 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2835 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2836 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2837 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2838 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2839 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2840 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);
2847 void R_ShadowVolumeLighting(int visiblevolumes)
2853 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2854 R_Shadow_EditLights_Reload_f();
2858 memset(&m, 0, sizeof(m));
2861 GL_BlendFunc(GL_ONE, GL_ONE);
2862 GL_DepthMask(false);
2863 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2864 qglDisable(GL_CULL_FACE);
2865 GL_Color(0.0, 0.0125, 0.1, 1);
2868 R_Shadow_Stage_Begin();
2869 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2870 if (r_shadow_debuglight.integer >= 0)
2872 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2873 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2874 R_DrawRTLight(&light->rtlight, visiblevolumes);
2877 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2878 if (light->flags & flag)
2879 R_DrawRTLight(&light->rtlight, visiblevolumes);
2881 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2882 R_DrawRTLight(&light->rtlight, visiblevolumes);
2886 qglEnable(GL_CULL_FACE);
2887 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2890 R_Shadow_Stage_End();
2893 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2894 typedef struct suffixinfo_s
2897 qboolean flipx, flipy, flipdiagonal;
2900 static suffixinfo_t suffix[3][6] =
2903 {"px", false, false, false},
2904 {"nx", false, false, false},
2905 {"py", false, false, false},
2906 {"ny", false, false, false},
2907 {"pz", false, false, false},
2908 {"nz", false, false, false}
2911 {"posx", false, false, false},
2912 {"negx", false, false, false},
2913 {"posy", false, false, false},
2914 {"negy", false, false, false},
2915 {"posz", false, false, false},
2916 {"negz", false, false, false}
2919 {"rt", true, false, true},
2920 {"lf", false, true, true},
2921 {"ft", true, true, false},
2922 {"bk", false, false, false},
2923 {"up", true, false, true},
2924 {"dn", true, false, true}
2928 static int componentorder[4] = {0, 1, 2, 3};
2930 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2932 int i, j, cubemapsize;
2933 qbyte *cubemappixels, *image_rgba;
2934 rtexture_t *cubemaptexture;
2936 // must start 0 so the first loadimagepixels has no requested width/height
2938 cubemappixels = NULL;
2939 cubemaptexture = NULL;
2940 // keep trying different suffix groups (posx, px, rt) until one loads
2941 for (j = 0;j < 3 && !cubemappixels;j++)
2943 // load the 6 images in the suffix group
2944 for (i = 0;i < 6;i++)
2946 // generate an image name based on the base and and suffix
2947 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2949 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2951 // an image loaded, make sure width and height are equal
2952 if (image_width == image_height)
2954 // if this is the first image to load successfully, allocate the cubemap memory
2955 if (!cubemappixels && image_width >= 1)
2957 cubemapsize = image_width;
2958 // note this clears to black, so unavailable sides are black
2959 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2961 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2963 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);
2966 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2968 Mem_Free(image_rgba);
2972 // if a cubemap loaded, upload it
2975 if (!r_shadow_filters_texturepool)
2976 r_shadow_filters_texturepool = R_AllocTexturePool();
2977 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2978 Mem_Free(cubemappixels);
2982 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2983 for (j = 0;j < 3;j++)
2984 for (i = 0;i < 6;i++)
2985 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2986 Con_Print(" and was unable to find any of them.\n");
2988 return cubemaptexture;
2991 rtexture_t *R_Shadow_Cubemap(const char *basename)
2994 for (i = 0;i < numcubemaps;i++)
2995 if (!strcasecmp(cubemaps[i].basename, basename))
2996 return cubemaps[i].texture;
2997 if (i >= MAX_CUBEMAPS)
3000 strcpy(cubemaps[i].basename, basename);
3001 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3002 return cubemaps[i].texture;
3005 void R_Shadow_FreeCubemaps(void)
3008 R_FreeTexturePool(&r_shadow_filters_texturepool);
3011 dlight_t *R_Shadow_NewWorldLight(void)
3014 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3015 light->next = r_shadow_worldlightchain;
3016 r_shadow_worldlightchain = light;
3020 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)
3022 VectorCopy(origin, light->origin);
3023 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3024 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3025 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3026 light->color[0] = max(color[0], 0);
3027 light->color[1] = max(color[1], 0);
3028 light->color[2] = max(color[2], 0);
3029 light->radius = max(radius, 0);
3030 light->style = style;
3031 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3033 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3036 light->shadow = shadowenable;
3037 light->corona = corona;
3040 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
3041 light->coronasizescale = coronasizescale;
3042 light->ambientscale = ambientscale;
3043 light->diffusescale = diffusescale;
3044 light->specularscale = specularscale;
3045 light->flags = flags;
3046 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3048 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3051 void R_Shadow_FreeWorldLight(dlight_t *light)
3053 dlight_t **lightpointer;
3054 R_RTLight_Uncompile(&light->rtlight);
3055 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3056 if (*lightpointer != light)
3057 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3058 *lightpointer = light->next;
3062 void R_Shadow_ClearWorldLights(void)
3064 while (r_shadow_worldlightchain)
3065 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3066 r_shadow_selectedlight = NULL;
3067 R_Shadow_FreeCubemaps();
3070 void R_Shadow_SelectLight(dlight_t *light)
3072 if (r_shadow_selectedlight)
3073 r_shadow_selectedlight->selected = false;
3074 r_shadow_selectedlight = light;
3075 if (r_shadow_selectedlight)
3076 r_shadow_selectedlight->selected = true;
3079 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3081 float scale = r_editlights_cursorgrid.value * 0.5f;
3082 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);
3085 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3088 const dlight_t *light;
3091 if (light->selected)
3092 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3095 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);
3098 void R_Shadow_DrawLightSprites(void)
3104 for (i = 0;i < 5;i++)
3106 lighttextures[i] = NULL;
3107 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3108 lighttextures[i] = pic->tex;
3111 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3112 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3113 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3116 void R_Shadow_SelectLightInView(void)
3118 float bestrating, rating, temp[3];
3119 dlight_t *best, *light;
3122 for (light = r_shadow_worldlightchain;light;light = light->next)
3124 VectorSubtract(light->origin, r_vieworigin, temp);
3125 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3128 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3129 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3131 bestrating = rating;
3136 R_Shadow_SelectLight(best);
3139 void R_Shadow_LoadWorldLights(void)
3141 int n, a, style, shadow, flags;
3142 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3143 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3144 if (r_refdef.worldmodel == NULL)
3146 Con_Print("No map loaded.\n");
3149 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3150 strlcat (name, ".rtlights", sizeof (name));
3151 lightsstring = FS_LoadFile(name, tempmempool, false);
3161 for (;COM_Parse(t, true) && strcmp(
3162 if (COM_Parse(t, true))
3164 if (com_token[0] == '!')
3167 origin[0] = atof(com_token+1);
3170 origin[0] = atof(com_token);
3175 while (*s && *s != '\n' && *s != '\r')
3181 // check for modifier flags
3188 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);
3191 flags = LIGHTFLAG_REALTIMEMODE;
3199 coronasizescale = 0.25f;
3201 VectorClear(angles);
3204 if (a < 9 || !strcmp(cubemapname, "\"\""))
3206 // remove quotes on cubemapname
3207 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3209 cubemapname[strlen(cubemapname)-1] = 0;
3210 strcpy(cubemapname, cubemapname + 1);
3214 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);
3217 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3218 radius *= r_editlights_rtlightssizescale.value;
3219 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3227 Con_Printf("invalid rtlights file \"%s\"\n", name);
3228 Mem_Free(lightsstring);
3232 void R_Shadow_SaveWorldLights(void)
3235 int bufchars, bufmaxchars;
3237 char name[MAX_QPATH];
3239 if (!r_shadow_worldlightchain)
3241 if (r_refdef.worldmodel == NULL)
3243 Con_Print("No map loaded.\n");
3246 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3247 strlcat (name, ".rtlights", sizeof (name));
3248 bufchars = bufmaxchars = 0;
3250 for (light = r_shadow_worldlightchain;light;light = light->next)
3252 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3253 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);
3254 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3255 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]);
3257 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);
3258 if (bufchars + (int) strlen(line) > bufmaxchars)
3260 bufmaxchars = bufchars + strlen(line) + 2048;
3262 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3266 memcpy(buf, oldbuf, bufchars);
3272 memcpy(buf + bufchars, line, strlen(line));
3273 bufchars += strlen(line);
3277 FS_WriteFile(name, buf, bufchars);
3282 void R_Shadow_LoadLightsFile(void)
3285 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3286 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3287 if (r_refdef.worldmodel == NULL)
3289 Con_Print("No map loaded.\n");
3292 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3293 strlcat (name, ".lights", sizeof (name));
3294 lightsstring = FS_LoadFile(name, tempmempool, false);
3302 while (*s && *s != '\n' && *s != '\r')
3308 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);
3312 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);
3315 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3316 radius = bound(15, radius, 4096);
3317 VectorScale(color, (2.0f / (8388608.0f)), color);
3318 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3326 Con_Printf("invalid lights file \"%s\"\n", name);
3327 Mem_Free(lightsstring);
3331 // tyrlite/hmap2 light types in the delay field
3332 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3334 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3336 int entnum, style, islight, skin, pflags, effects, type, n;
3339 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3340 char key[256], value[1024];
3342 if (r_refdef.worldmodel == NULL)
3344 Con_Print("No map loaded.\n");
3347 // try to load a .ent file first
3348 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3349 strlcat (key, ".ent", sizeof (key));
3350 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3351 // and if that is not found, fall back to the bsp file entity string
3353 data = r_refdef.worldmodel->brush.entities;
3356 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3358 type = LIGHTTYPE_MINUSX;
3359 origin[0] = origin[1] = origin[2] = 0;
3360 originhack[0] = originhack[1] = originhack[2] = 0;
3361 angles[0] = angles[1] = angles[2] = 0;
3362 color[0] = color[1] = color[2] = 1;
3363 light[0] = light[1] = light[2] = 1;light[3] = 300;
3364 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3374 if (!COM_ParseToken(&data, false))
3376 if (com_token[0] == '}')
3377 break; // end of entity
3378 if (com_token[0] == '_')
3379 strcpy(key, com_token + 1);
3381 strcpy(key, com_token);
3382 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3383 key[strlen(key)-1] = 0;
3384 if (!COM_ParseToken(&data, false))
3386 strcpy(value, com_token);
3388 // now that we have the key pair worked out...
3389 if (!strcmp("light", key))
3391 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3395 light[0] = vec[0] * (1.0f / 256.0f);
3396 light[1] = vec[0] * (1.0f / 256.0f);
3397 light[2] = vec[0] * (1.0f / 256.0f);
3403 light[0] = vec[0] * (1.0f / 255.0f);
3404 light[1] = vec[1] * (1.0f / 255.0f);
3405 light[2] = vec[2] * (1.0f / 255.0f);
3409 else if (!strcmp("delay", key))
3411 else if (!strcmp("origin", key))
3412 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3413 else if (!strcmp("angle", key))
3414 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3415 else if (!strcmp("angles", key))
3416 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3417 else if (!strcmp("color", key))
3418 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3419 else if (!strcmp("wait", key))
3420 fadescale = atof(value);
3421 else if (!strcmp("classname", key))
3423 if (!strncmp(value, "light", 5))
3426 if (!strcmp(value, "light_fluoro"))
3431 overridecolor[0] = 1;
3432 overridecolor[1] = 1;
3433 overridecolor[2] = 1;
3435 if (!strcmp(value, "light_fluorospark"))
3440 overridecolor[0] = 1;
3441 overridecolor[1] = 1;
3442 overridecolor[2] = 1;
3444 if (!strcmp(value, "light_globe"))
3449 overridecolor[0] = 1;
3450 overridecolor[1] = 0.8;
3451 overridecolor[2] = 0.4;
3453 if (!strcmp(value, "light_flame_large_yellow"))
3458 overridecolor[0] = 1;
3459 overridecolor[1] = 0.5;
3460 overridecolor[2] = 0.1;
3462 if (!strcmp(value, "light_flame_small_yellow"))
3467 overridecolor[0] = 1;
3468 overridecolor[1] = 0.5;
3469 overridecolor[2] = 0.1;
3471 if (!strcmp(value, "light_torch_small_white"))
3476 overridecolor[0] = 1;
3477 overridecolor[1] = 0.5;
3478 overridecolor[2] = 0.1;
3480 if (!strcmp(value, "light_torch_small_walltorch"))
3485 overridecolor[0] = 1;
3486 overridecolor[1] = 0.5;
3487 overridecolor[2] = 0.1;
3491 else if (!strcmp("style", key))
3492 style = atoi(value);
3493 else if (r_refdef.worldmodel->type == mod_brushq3)
3495 if (!strcmp("scale", key))
3496 lightscale = atof(value);
3497 if (!strcmp("fade", key))
3498 fadescale = atof(value);
3500 else if (!strcmp("skin", key))
3501 skin = (int)atof(value);
3502 else if (!strcmp("pflags", key))
3503 pflags = (int)atof(value);
3504 else if (!strcmp("effects", key))
3505 effects = (int)atof(value);
3509 if (lightscale <= 0)
3513 if (color[0] == color[1] && color[0] == color[2])
3515 color[0] *= overridecolor[0];
3516 color[1] *= overridecolor[1];
3517 color[2] *= overridecolor[2];
3519 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3520 color[0] = color[0] * light[0];
3521 color[1] = color[1] * light[1];
3522 color[2] = color[2] * light[2];
3525 case LIGHTTYPE_MINUSX:
3527 case LIGHTTYPE_RECIPX:
3529 VectorScale(color, (1.0f / 16.0f), color);
3531 case LIGHTTYPE_RECIPXX:
3533 VectorScale(color, (1.0f / 16.0f), color);
3536 case LIGHTTYPE_NONE:
3540 case LIGHTTYPE_MINUSXX:
3543 VectorAdd(origin, originhack, origin);
3545 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);
3548 Mem_Free(entfiledata);
3552 void R_Shadow_SetCursorLocationForView(void)
3554 vec_t dist, push, frac;
3555 vec3_t dest, endpos, normal;
3556 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3557 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3560 dist = frac * r_editlights_cursordistance.value;
3561 push = r_editlights_cursorpushback.value;
3565 VectorMA(endpos, push, r_viewforward, endpos);
3566 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3568 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3569 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3570 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3573 void R_Shadow_UpdateWorldLightSelection(void)
3575 if (r_editlights.integer)
3577 R_Shadow_SetCursorLocationForView();
3578 R_Shadow_SelectLightInView();
3579 R_Shadow_DrawLightSprites();
3582 R_Shadow_SelectLight(NULL);
3585 void R_Shadow_EditLights_Clear_f(void)
3587 R_Shadow_ClearWorldLights();
3590 void R_Shadow_EditLights_Reload_f(void)
3592 if (!r_refdef.worldmodel)
3594 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3595 R_Shadow_ClearWorldLights();
3596 R_Shadow_LoadWorldLights();
3597 if (r_shadow_worldlightchain == NULL)
3599 R_Shadow_LoadLightsFile();
3600 if (r_shadow_worldlightchain == NULL)
3601 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3605 void R_Shadow_EditLights_Save_f(void)
3607 if (!r_refdef.worldmodel)
3609 R_Shadow_SaveWorldLights();
3612 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3614 R_Shadow_ClearWorldLights();
3615 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3618 void R_Shadow_EditLights_ImportLightsFile_f(void)
3620 R_Shadow_ClearWorldLights();
3621 R_Shadow_LoadLightsFile();
3624 void R_Shadow_EditLights_Spawn_f(void)
3627 if (!r_editlights.integer)
3629 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3632 if (Cmd_Argc() != 1)
3634 Con_Print("r_editlights_spawn does not take parameters\n");
3637 color[0] = color[1] = color[2] = 1;
3638 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3641 void R_Shadow_EditLights_Edit_f(void)
3643 vec3_t origin, angles, color;
3644 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3645 int style, shadows, flags, normalmode, realtimemode;
3646 char cubemapname[1024];
3647 if (!r_editlights.integer)
3649 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3652 if (!r_shadow_selectedlight)
3654 Con_Print("No selected light.\n");
3657 VectorCopy(r_shadow_selectedlight->origin, origin);
3658 VectorCopy(r_shadow_selectedlight->angles, angles);
3659 VectorCopy(r_shadow_selectedlight->color, color);
3660 radius = r_shadow_selectedlight->radius;
3661 style = r_shadow_selectedlight->style;
3662 if (r_shadow_selectedlight->cubemapname)
3663 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3666 shadows = r_shadow_selectedlight->shadow;
3667 corona = r_shadow_selectedlight->corona;
3668 coronasizescale = r_shadow_selectedlight->coronasizescale;
3669 ambientscale = r_shadow_selectedlight->ambientscale;
3670 diffusescale = r_shadow_selectedlight->diffusescale;
3671 specularscale = r_shadow_selectedlight->specularscale;
3672 flags = r_shadow_selectedlight->flags;
3673 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3674 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3675 if (!strcmp(Cmd_Argv(1), "origin"))
3677 if (Cmd_Argc() != 5)
3679 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3682 origin[0] = atof(Cmd_Argv(2));
3683 origin[1] = atof(Cmd_Argv(3));
3684 origin[2] = atof(Cmd_Argv(4));
3686 else if (!strcmp(Cmd_Argv(1), "originx"))
3688 if (Cmd_Argc() != 3)
3690 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3693 origin[0] = atof(Cmd_Argv(2));
3695 else if (!strcmp(Cmd_Argv(1), "originy"))
3697 if (Cmd_Argc() != 3)
3699 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3702 origin[1] = atof(Cmd_Argv(2));
3704 else if (!strcmp(Cmd_Argv(1), "originz"))
3706 if (Cmd_Argc() != 3)
3708 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3711 origin[2] = atof(Cmd_Argv(2));
3713 else if (!strcmp(Cmd_Argv(1), "move"))
3715 if (Cmd_Argc() != 5)
3717 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3720 origin[0] += atof(Cmd_Argv(2));
3721 origin[1] += atof(Cmd_Argv(3));
3722 origin[2] += atof(Cmd_Argv(4));
3724 else if (!strcmp(Cmd_Argv(1), "movex"))
3726 if (Cmd_Argc() != 3)
3728 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3731 origin[0] += atof(Cmd_Argv(2));
3733 else if (!strcmp(Cmd_Argv(1), "movey"))
3735 if (Cmd_Argc() != 3)
3737 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3740 origin[1] += atof(Cmd_Argv(2));
3742 else if (!strcmp(Cmd_Argv(1), "movez"))
3744 if (Cmd_Argc() != 3)
3746 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3749 origin[2] += atof(Cmd_Argv(2));
3751 else if (!strcmp(Cmd_Argv(1), "angles"))
3753 if (Cmd_Argc() != 5)
3755 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3758 angles[0] = atof(Cmd_Argv(2));
3759 angles[1] = atof(Cmd_Argv(3));
3760 angles[2] = atof(Cmd_Argv(4));
3762 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3764 if (Cmd_Argc() != 3)
3766 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3769 angles[0] = atof(Cmd_Argv(2));
3771 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3773 if (Cmd_Argc() != 3)
3775 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3778 angles[1] = atof(Cmd_Argv(2));
3780 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3782 if (Cmd_Argc() != 3)
3784 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3787 angles[2] = atof(Cmd_Argv(2));
3789 else if (!strcmp(Cmd_Argv(1), "color"))
3791 if (Cmd_Argc() != 5)
3793 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3796 color[0] = atof(Cmd_Argv(2));
3797 color[1] = atof(Cmd_Argv(3));
3798 color[2] = atof(Cmd_Argv(4));
3800 else if (!strcmp(Cmd_Argv(1), "radius"))
3802 if (Cmd_Argc() != 3)
3804 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3807 radius = atof(Cmd_Argv(2));
3809 else if (!strcmp(Cmd_Argv(1), "style"))
3811 if (Cmd_Argc() != 3)
3813 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3816 style = atoi(Cmd_Argv(2));
3818 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3822 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3825 if (Cmd_Argc() == 3)
3826 strcpy(cubemapname, Cmd_Argv(2));
3830 else if (!strcmp(Cmd_Argv(1), "shadows"))
3832 if (Cmd_Argc() != 3)
3834 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3837 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3839 else if (!strcmp(Cmd_Argv(1), "corona"))
3841 if (Cmd_Argc() != 3)
3843 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3846 corona = atof(Cmd_Argv(2));
3848 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3850 if (Cmd_Argc() != 3)
3852 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3855 coronasizescale = atof(Cmd_Argv(2));
3857 else if (!strcmp(Cmd_Argv(1), "ambient"))
3859 if (Cmd_Argc() != 3)
3861 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3864 ambientscale = atof(Cmd_Argv(2));
3866 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3868 if (Cmd_Argc() != 3)
3870 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3873 diffusescale = atof(Cmd_Argv(2));
3875 else if (!strcmp(Cmd_Argv(1), "specular"))
3877 if (Cmd_Argc() != 3)
3879 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3882 specularscale = atof(Cmd_Argv(2));
3884 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3886 if (Cmd_Argc() != 3)
3888 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3891 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3893 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3895 if (Cmd_Argc() != 3)
3897 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3900 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3904 Con_Print("usage: r_editlights_edit [property] [value]\n");
3905 Con_Print("Selected light's properties:\n");
3906 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3907 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3908 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3909 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3910 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3911 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3912 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3913 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3914 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3915 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3916 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3917 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3918 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3919 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3922 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3923 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3926 void R_Shadow_EditLights_EditAll_f(void)
3930 if (!r_editlights.integer)
3932 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3936 for (light = r_shadow_worldlightchain;light;light = light->next)
3938 R_Shadow_SelectLight(light);
3939 R_Shadow_EditLights_Edit_f();
3943 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3945 int lightnumber, lightcount;
3949 if (!r_editlights.integer)
3955 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3956 if (light == r_shadow_selectedlight)
3957 lightnumber = lightcount;
3958 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;
3959 if (r_shadow_selectedlight == NULL)
3961 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3962 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;
3963 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;
3964 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;
3965 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3966 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3967 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3968 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;
3969 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3970 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3971 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3972 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3973 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3974 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;
3975 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;
3978 void R_Shadow_EditLights_ToggleShadow_f(void)
3980 if (!r_editlights.integer)
3982 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3985 if (!r_shadow_selectedlight)
3987 Con_Print("No selected light.\n");
3990 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);
3993 void R_Shadow_EditLights_ToggleCorona_f(void)
3995 if (!r_editlights.integer)
3997 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4000 if (!r_shadow_selectedlight)
4002 Con_Print("No selected light.\n");
4005 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);
4008 void R_Shadow_EditLights_Remove_f(void)
4010 if (!r_editlights.integer)
4012 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4015 if (!r_shadow_selectedlight)
4017 Con_Print("No selected light.\n");
4020 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4021 r_shadow_selectedlight = NULL;
4024 void R_Shadow_EditLights_Help_f(void)
4027 "Documentation on r_editlights system:\n"
4029 "r_editlights : enable/disable editing mode\n"
4030 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4031 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4032 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4033 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4034 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4035 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4036 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4038 "r_editlights_help : this help\n"
4039 "r_editlights_clear : remove all lights\n"
4040 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4041 "r_editlights_save : save to .rtlights file\n"
4042 "r_editlights_spawn : create a light with default settings\n"
4043 "r_editlights_edit command : edit selected light - more documentation below\n"
4044 "r_editlights_remove : remove selected light\n"
4045 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4046 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4047 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4049 "origin x y z : set light location\n"
4050 "originx x: set x component of light location\n"
4051 "originy y: set y component of light location\n"
4052 "originz z: set z component of light location\n"
4053 "move x y z : adjust light location\n"
4054 "movex x: adjust x component of light location\n"
4055 "movey y: adjust y component of light location\n"
4056 "movez z: adjust z component of light location\n"
4057 "angles x y z : set light angles\n"
4058 "anglesx x: set x component of light angles\n"
4059 "anglesy y: set y component of light angles\n"
4060 "anglesz z: set z component of light angles\n"
4061 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4062 "radius radius : set radius (size) of light\n"
4063 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4064 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4065 "shadows 1/0 : turn on/off shadows\n"
4066 "corona n : set corona intensity\n"
4067 "coronasize n : set corona size (0-1)\n"
4068 "ambient n : set ambient intensity (0-1)\n"
4069 "diffuse n : set diffuse intensity (0-1)\n"
4070 "specular n : set specular intensity (0-1)\n"
4071 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4072 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4073 "<nothing> : print light properties to console\n"
4077 void R_Shadow_EditLights_CopyInfo_f(void)
4079 if (!r_editlights.integer)
4081 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4084 if (!r_shadow_selectedlight)
4086 Con_Print("No selected light.\n");
4089 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4090 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4091 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4092 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4093 if (r_shadow_selectedlight->cubemapname)
4094 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4096 r_shadow_bufferlight.cubemapname[0] = 0;
4097 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4098 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4099 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4100 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4101 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4102 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4103 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4106 void R_Shadow_EditLights_PasteInfo_f(void)
4108 if (!r_editlights.integer)
4110 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4113 if (!r_shadow_selectedlight)
4115 Con_Print("No selected light.\n");
4118 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);
4121 void R_Shadow_EditLights_Init(void)
4123 Cvar_RegisterVariable(&r_editlights);
4124 Cvar_RegisterVariable(&r_editlights_cursordistance);
4125 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4126 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4127 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4128 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4129 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4130 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4131 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4132 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4133 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4134 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4135 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4136 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4137 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4138 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4139 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4140 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4141 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4142 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4143 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4144 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);