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.02"};
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 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
359 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
360 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
361 " TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
364 "#ifdef USECUBEFILTER\n"
365 " // apply light cubemap filter\n"
366 " LightColor *= vec3(textureCube(Texture_Cube, CubeVector));\n"
369 " // get the texels - with a blendmap we'd need to blend multiple here\n"
370 " vec3 surfacenormal = vec3(texture2D(Texture_Normal, TexCoord)) * 2.0 - 1.0;\n"
371 " vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
372 "#ifdef USESPECULAR\n"
373 " vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
376 " // calculate shading\n"
377 " vec3 diffusenormal = normalize(LightVector);\n"
378 " vec3 color = colortexel * (AmbientScale + DiffuseScale * clamp(dot(surfacenormal, diffusenormal), 0.0, 1.0));\n"
379 "#ifdef USESPECULAR\n"
380 " color += glosstexel * (SpecularScale * pow(clamp(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0, 1.0), SpecularPower));\n"
383 " // calculate fragment color\n"
384 " gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
388 void r_shadow_start(void)
391 // allocate vertex processing arrays
393 r_shadow_normalcubetexture = NULL;
394 r_shadow_attenuation2dtexture = NULL;
395 r_shadow_attenuation3dtexture = NULL;
396 r_shadow_blankbumptexture = NULL;
397 r_shadow_blankglosstexture = NULL;
398 r_shadow_blankwhitetexture = NULL;
399 r_shadow_blankwhitecubetexture = NULL;
400 r_shadow_blankblacktexture = NULL;
401 r_shadow_texturepool = NULL;
402 r_shadow_filters_texturepool = NULL;
403 R_Shadow_ValidateCvars();
404 R_Shadow_MakeTextures();
405 maxshadowelements = 0;
406 shadowelements = NULL;
414 shadowmarklist = NULL;
416 r_shadow_buffer_numclusterpvsbytes = 0;
417 r_shadow_buffer_clusterpvs = NULL;
418 r_shadow_buffer_clusterlist = NULL;
419 r_shadow_buffer_numsurfacepvsbytes = 0;
420 r_shadow_buffer_surfacepvs = NULL;
421 r_shadow_buffer_surfacelist = NULL;
422 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
423 r_shadow_program_light[i] = 0;
424 if (gl_support_fragment_shader)
426 char *vertstring, *fragstring;
427 int vertstrings_count;
428 int fragstrings_count;
429 const char *vertstrings_list[SHADERPERMUTATION_COUNT];
430 const char *fragstrings_list[SHADERPERMUTATION_COUNT];
431 vertstring = FS_LoadFile("glsl/light.vert", tempmempool, false);
432 fragstring = FS_LoadFile("glsl/light.frag", tempmempool, false);
433 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
435 vertstrings_count = 0;
436 fragstrings_count = 0;
437 if (i & SHADERPERMUTATION_SPECULAR)
439 vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
440 fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
442 if (i & SHADERPERMUTATION_FOG)
444 vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
445 fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
447 if (i & SHADERPERMUTATION_CUBEFILTER)
449 vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
450 fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
452 if (i & SHADERPERMUTATION_OFFSETMAPPING)
454 vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
455 fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
457 vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
458 fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
459 r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
460 qglUseProgramObjectARB(r_shadow_program_light[i]);
461 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
462 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
463 if (i & SHADERPERMUTATION_SPECULAR)
465 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
467 if (i & SHADERPERMUTATION_CUBEFILTER)
469 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
471 if (i & SHADERPERMUTATION_FOG)
473 qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
477 Mem_Free(fragstring);
479 Mem_Free(vertstring);
483 void r_shadow_shutdown(void)
486 R_Shadow_UncompileWorldLights();
487 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
489 if (r_shadow_program_light[i])
491 GL_Backend_FreeProgram(r_shadow_program_light[i]);
492 r_shadow_program_light[i] = 0;
496 r_shadow_normalcubetexture = NULL;
497 r_shadow_attenuation2dtexture = NULL;
498 r_shadow_attenuation3dtexture = NULL;
499 r_shadow_blankbumptexture = NULL;
500 r_shadow_blankglosstexture = NULL;
501 r_shadow_blankwhitetexture = NULL;
502 r_shadow_blankwhitecubetexture = NULL;
503 r_shadow_blankblacktexture = NULL;
504 R_FreeTexturePool(&r_shadow_texturepool);
505 R_FreeTexturePool(&r_shadow_filters_texturepool);
506 maxshadowelements = 0;
508 Mem_Free(shadowelements);
509 shadowelements = NULL;
512 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
521 Mem_Free(shadowmark);
524 Mem_Free(shadowmarklist);
525 shadowmarklist = NULL;
527 r_shadow_buffer_numclusterpvsbytes = 0;
528 if (r_shadow_buffer_clusterpvs)
529 Mem_Free(r_shadow_buffer_clusterpvs);
530 r_shadow_buffer_clusterpvs = NULL;
531 if (r_shadow_buffer_clusterlist)
532 Mem_Free(r_shadow_buffer_clusterlist);
533 r_shadow_buffer_clusterlist = NULL;
534 r_shadow_buffer_numsurfacepvsbytes = 0;
535 if (r_shadow_buffer_surfacepvs)
536 Mem_Free(r_shadow_buffer_surfacepvs);
537 r_shadow_buffer_surfacepvs = NULL;
538 if (r_shadow_buffer_surfacelist)
539 Mem_Free(r_shadow_buffer_surfacelist);
540 r_shadow_buffer_surfacelist = NULL;
543 void r_shadow_newmap(void)
547 void R_Shadow_Help_f(void)
550 "Documentation on r_shadow system:\n"
552 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
553 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
554 "r_shadow_debuglight : render only this light number (-1 = all)\n"
555 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
556 "r_shadow_gloss2intensity : brightness of forced gloss\n"
557 "r_shadow_glossintensity : brightness of textured gloss\n"
558 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
559 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
560 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
561 "r_shadow_portallight : use portal visibility for static light precomputation\n"
562 "r_shadow_projectdistance : shadow volume projection distance\n"
563 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
564 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
565 "r_shadow_realtime_world : use high quality world lighting mode\n"
566 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
567 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
568 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
569 "r_shadow_scissor : use scissor optimization\n"
570 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
571 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
572 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
573 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
574 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
576 "r_shadow_help : this help\n"
580 void R_Shadow_Init(void)
582 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
583 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
584 Cvar_RegisterVariable(&r_shadow_cull);
585 Cvar_RegisterVariable(&r_shadow_debuglight);
586 Cvar_RegisterVariable(&r_shadow_gloss);
587 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
588 Cvar_RegisterVariable(&r_shadow_glossintensity);
589 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
590 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
591 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
592 Cvar_RegisterVariable(&r_shadow_portallight);
593 Cvar_RegisterVariable(&r_shadow_projectdistance);
594 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
595 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
596 Cvar_RegisterVariable(&r_shadow_realtime_world);
597 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
598 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
599 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
600 Cvar_RegisterVariable(&r_shadow_scissor);
601 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
602 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
603 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
604 Cvar_RegisterVariable(&r_shadow_staticworldlights);
605 Cvar_RegisterVariable(&r_shadow_texture3d);
606 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
607 Cvar_RegisterVariable(&r_shadow_glsl);
608 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
609 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
610 Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
611 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
612 if (gamemode == GAME_TENEBRAE)
614 Cvar_SetValue("r_shadow_gloss", 2);
615 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
617 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
618 R_Shadow_EditLights_Init();
619 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
620 r_shadow_worldlightchain = NULL;
621 maxshadowelements = 0;
622 shadowelements = NULL;
630 shadowmarklist = NULL;
632 r_shadow_buffer_numclusterpvsbytes = 0;
633 r_shadow_buffer_clusterpvs = NULL;
634 r_shadow_buffer_clusterlist = NULL;
635 r_shadow_buffer_numsurfacepvsbytes = 0;
636 r_shadow_buffer_surfacepvs = NULL;
637 r_shadow_buffer_surfacelist = NULL;
638 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
641 matrix4x4_t matrix_attenuationxyz =
644 {0.5, 0.0, 0.0, 0.5},
645 {0.0, 0.5, 0.0, 0.5},
646 {0.0, 0.0, 0.5, 0.5},
651 matrix4x4_t matrix_attenuationz =
654 {0.0, 0.0, 0.5, 0.5},
655 {0.0, 0.0, 0.0, 0.5},
656 {0.0, 0.0, 0.0, 0.5},
661 int *R_Shadow_ResizeShadowElements(int numtris)
663 // make sure shadowelements is big enough for this volume
664 if (maxshadowelements < numtris * 24)
666 maxshadowelements = numtris * 24;
668 Mem_Free(shadowelements);
669 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
671 return shadowelements;
674 void R_Shadow_EnlargeClusterBuffer(int numclusters)
676 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
677 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
679 if (r_shadow_buffer_clusterpvs)
680 Mem_Free(r_shadow_buffer_clusterpvs);
681 if (r_shadow_buffer_clusterlist)
682 Mem_Free(r_shadow_buffer_clusterlist);
683 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
684 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
685 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
689 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
691 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
692 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
694 if (r_shadow_buffer_surfacepvs)
695 Mem_Free(r_shadow_buffer_surfacepvs);
696 if (r_shadow_buffer_surfacelist)
697 Mem_Free(r_shadow_buffer_surfacelist);
698 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
699 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
700 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
704 void R_Shadow_PrepareShadowMark(int numtris)
706 // make sure shadowmark is big enough for this volume
707 if (maxshadowmark < numtris)
709 maxshadowmark = numtris;
711 Mem_Free(shadowmark);
713 Mem_Free(shadowmarklist);
714 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
715 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
719 // if shadowmarkcount wrapped we clear the array and adjust accordingly
720 if (shadowmarkcount == 0)
723 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
728 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)
730 int i, j, tris = 0, vr[3], t, outvertices = 0;
735 if (maxvertexupdate < innumvertices)
737 maxvertexupdate = innumvertices;
739 Mem_Free(vertexupdate);
741 Mem_Free(vertexremap);
742 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
743 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
747 if (vertexupdatenum == 0)
750 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
751 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
754 for (i = 0;i < numshadowmarktris;i++)
755 shadowmark[shadowmarktris[i]] = shadowmarkcount;
757 for (i = 0;i < numshadowmarktris;i++)
759 t = shadowmarktris[i];
760 e = inelement3i + t * 3;
761 // make sure the vertices are created
762 for (j = 0;j < 3;j++)
764 if (vertexupdate[e[j]] != vertexupdatenum)
766 vertexupdate[e[j]] = vertexupdatenum;
767 vertexremap[e[j]] = outvertices;
768 v = invertex3f + e[j] * 3;
769 // project one copy of the vertex to the sphere radius of the light
770 // (FIXME: would projecting it to the light box be better?)
771 VectorSubtract(v, projectorigin, temp);
772 f = projectdistance / VectorLength(temp);
773 VectorCopy(v, outvertex3f);
774 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
781 for (i = 0;i < numshadowmarktris;i++)
783 t = shadowmarktris[i];
784 e = inelement3i + t * 3;
785 n = inneighbor3i + t * 3;
786 // output the front and back triangles
787 outelement3i[0] = vertexremap[e[0]];
788 outelement3i[1] = vertexremap[e[1]];
789 outelement3i[2] = vertexremap[e[2]];
790 outelement3i[3] = vertexremap[e[2]] + 1;
791 outelement3i[4] = vertexremap[e[1]] + 1;
792 outelement3i[5] = vertexremap[e[0]] + 1;
795 // output the sides (facing outward from this triangle)
796 if (shadowmark[n[0]] != shadowmarkcount)
798 vr[0] = vertexremap[e[0]];
799 vr[1] = vertexremap[e[1]];
800 outelement3i[0] = vr[1];
801 outelement3i[1] = vr[0];
802 outelement3i[2] = vr[0] + 1;
803 outelement3i[3] = vr[1];
804 outelement3i[4] = vr[0] + 1;
805 outelement3i[5] = vr[1] + 1;
809 if (shadowmark[n[1]] != shadowmarkcount)
811 vr[1] = vertexremap[e[1]];
812 vr[2] = vertexremap[e[2]];
813 outelement3i[0] = vr[2];
814 outelement3i[1] = vr[1];
815 outelement3i[2] = vr[1] + 1;
816 outelement3i[3] = vr[2];
817 outelement3i[4] = vr[1] + 1;
818 outelement3i[5] = vr[2] + 1;
822 if (shadowmark[n[2]] != shadowmarkcount)
824 vr[0] = vertexremap[e[0]];
825 vr[2] = vertexremap[e[2]];
826 outelement3i[0] = vr[0];
827 outelement3i[1] = vr[2];
828 outelement3i[2] = vr[2] + 1;
829 outelement3i[3] = vr[0];
830 outelement3i[4] = vr[2] + 1;
831 outelement3i[5] = vr[0] + 1;
837 *outnumvertices = outvertices;
841 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)
844 if (projectdistance < 0.1)
846 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
849 if (!numverts || !nummarktris)
851 // make sure shadowelements is big enough for this volume
852 if (maxshadowelements < nummarktris * 24)
853 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
854 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
855 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
858 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)
863 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
865 tend = firsttriangle + numtris;
866 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
867 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
868 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
870 // surface box entirely inside light box, no box cull
871 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
872 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
873 shadowmarklist[numshadowmark++] = t;
877 // surface box not entirely inside light box, cull each triangle
878 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
880 v[0] = invertex3f + e[0] * 3;
881 v[1] = invertex3f + e[1] * 3;
882 v[2] = invertex3f + e[2] * 3;
883 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
884 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
885 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
886 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
887 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
888 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
889 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
890 shadowmarklist[numshadowmark++] = t;
895 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
898 if (r_shadow_compilingrtlight)
900 // if we're compiling an rtlight, capture the mesh
901 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
904 memset(&m, 0, sizeof(m));
905 m.pointer_vertex = vertex3f;
907 GL_LockArrays(0, numvertices);
908 if (r_shadowstage == SHADOWSTAGE_STENCIL)
910 // increment stencil if backface is behind depthbuffer
911 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
912 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
913 R_Mesh_Draw(numvertices, numtriangles, element3i);
915 c_rt_shadowtris += numtriangles;
916 // decrement stencil if frontface is behind depthbuffer
917 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
918 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
920 R_Mesh_Draw(numvertices, numtriangles, element3i);
922 c_rt_shadowtris += numtriangles;
926 static void R_Shadow_MakeTextures(void)
928 int x, y, z, d, side;
929 float v[3], s, t, intensity;
931 R_FreeTexturePool(&r_shadow_texturepool);
932 r_shadow_texturepool = R_AllocTexturePool();
933 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
934 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
936 #define ATTEN2DSIZE 64
937 #define ATTEN3DSIZE 32
938 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
943 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
948 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
953 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
958 r_shadow_blankblacktexture = R_LoadTexture2D(r_shadow_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
959 r_shadow_blankwhitecubetexture = NULL;
960 r_shadow_normalcubetexture = NULL;
961 if (gl_texturecubemap)
963 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
964 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
965 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
966 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
967 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
968 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
969 r_shadow_blankwhitecubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "blankwhitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
970 for (side = 0;side < 6;side++)
972 for (y = 0;y < NORMSIZE;y++)
974 for (x = 0;x < NORMSIZE;x++)
976 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
977 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
1011 intensity = 127.0f / sqrt(DotProduct(v, v));
1012 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
1013 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
1014 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
1015 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
1019 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
1021 for (y = 0;y < ATTEN2DSIZE;y++)
1023 for (x = 0;x < ATTEN2DSIZE;x++)
1025 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1026 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
1028 intensity = 1.0f - sqrt(DotProduct(v, v));
1030 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1031 d = bound(0, intensity, 255);
1032 data[(y*ATTEN2DSIZE+x)*4+0] = d;
1033 data[(y*ATTEN2DSIZE+x)*4+1] = d;
1034 data[(y*ATTEN2DSIZE+x)*4+2] = d;
1035 data[(y*ATTEN2DSIZE+x)*4+3] = d;
1038 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1039 if (r_shadow_texture3d.integer)
1041 for (z = 0;z < ATTEN3DSIZE;z++)
1043 for (y = 0;y < ATTEN3DSIZE;y++)
1045 for (x = 0;x < ATTEN3DSIZE;x++)
1047 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1048 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1049 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
1050 intensity = 1.0f - sqrt(DotProduct(v, v));
1052 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
1053 d = bound(0, intensity, 255);
1054 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
1055 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
1056 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
1057 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
1061 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1066 void R_Shadow_ValidateCvars(void)
1068 if (r_shadow_texture3d.integer && !gl_texture3d)
1069 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1070 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1071 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1074 void R_Shadow_Stage_Begin(void)
1078 R_Shadow_ValidateCvars();
1080 if (!r_shadow_attenuation2dtexture
1081 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1082 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
1083 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
1084 R_Shadow_MakeTextures();
1086 memset(&m, 0, sizeof(m));
1087 GL_BlendFunc(GL_ONE, GL_ZERO);
1088 GL_DepthMask(false);
1091 GL_Color(0, 0, 0, 1);
1092 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1093 qglEnable(GL_CULL_FACE);
1094 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1095 r_shadowstage = SHADOWSTAGE_NONE;
1098 void R_Shadow_Stage_ShadowVolumes(void)
1101 memset(&m, 0, sizeof(m));
1103 GL_Color(1, 1, 1, 1);
1104 GL_ColorMask(0, 0, 0, 0);
1105 GL_BlendFunc(GL_ONE, GL_ZERO);
1106 GL_DepthMask(false);
1108 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1109 //if (r_shadow_shadow_polygonoffset.value != 0)
1111 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
1112 // qglEnable(GL_POLYGON_OFFSET_FILL);
1115 // qglDisable(GL_POLYGON_OFFSET_FILL);
1116 qglDepthFunc(GL_LESS);
1117 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1118 qglEnable(GL_STENCIL_TEST);
1119 qglStencilFunc(GL_ALWAYS, 128, ~0);
1120 if (gl_ext_stenciltwoside.integer)
1122 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
1123 qglDisable(GL_CULL_FACE);
1124 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1125 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
1127 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
1128 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
1130 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
1134 r_shadowstage = SHADOWSTAGE_STENCIL;
1135 qglEnable(GL_CULL_FACE);
1137 // this is changed by every shadow render so its value here is unimportant
1138 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1140 GL_Clear(GL_STENCIL_BUFFER_BIT);
1142 // LordHavoc note: many shadow volumes reside entirely inside the world
1143 // (that is to say they are entirely bounded by their lit surfaces),
1144 // which can be optimized by handling things as an inverted light volume,
1145 // with the shadow boundaries of the world being simulated by an altered
1146 // (129) bias to stencil clearing on such lights
1147 // FIXME: generate inverted light volumes for use as shadow volumes and
1148 // optimize for them as noted above
1151 void R_Shadow_Stage_Light(int shadowtest)
1154 memset(&m, 0, sizeof(m));
1156 GL_BlendFunc(GL_ONE, GL_ONE);
1157 GL_DepthMask(false);
1159 qglPolygonOffset(0, 0);
1160 //qglDisable(GL_POLYGON_OFFSET_FILL);
1161 GL_Color(1, 1, 1, 1);
1162 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1163 qglDepthFunc(GL_EQUAL);
1164 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1165 qglEnable(GL_CULL_FACE);
1167 qglEnable(GL_STENCIL_TEST);
1169 qglDisable(GL_STENCIL_TEST);
1170 if (gl_support_stenciltwoside)
1171 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1173 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1174 // only draw light where this geometry was already rendered AND the
1175 // stencil is 128 (values other than this mean shadow)
1176 qglStencilFunc(GL_EQUAL, 128, ~0);
1177 r_shadowstage = SHADOWSTAGE_LIGHT;
1181 void R_Shadow_Stage_End(void)
1184 memset(&m, 0, sizeof(m));
1186 GL_BlendFunc(GL_ONE, GL_ZERO);
1189 qglPolygonOffset(0, 0);
1190 //qglDisable(GL_POLYGON_OFFSET_FILL);
1191 GL_Color(1, 1, 1, 1);
1192 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1193 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1194 qglDepthFunc(GL_LEQUAL);
1195 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1196 qglDisable(GL_STENCIL_TEST);
1197 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1198 if (gl_support_stenciltwoside)
1199 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1201 qglStencilFunc(GL_ALWAYS, 128, ~0);
1202 r_shadowstage = SHADOWSTAGE_NONE;
1205 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1207 int i, ix1, iy1, ix2, iy2;
1208 float x1, y1, x2, y2, x, y, f;
1209 vec3_t smins, smaxs;
1211 if (!r_shadow_scissor.integer)
1213 // if view is inside the box, just say yes it's visible
1214 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1216 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1219 for (i = 0;i < 3;i++)
1221 if (r_viewforward[i] >= 0)
1232 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1233 if (DotProduct(r_viewforward, v2) <= f)
1235 // entirely behind nearclip plane
1238 if (DotProduct(r_viewforward, v) >= f)
1240 // entirely infront of nearclip plane
1241 x1 = y1 = x2 = y2 = 0;
1242 for (i = 0;i < 8;i++)
1244 v[0] = (i & 1) ? mins[0] : maxs[0];
1245 v[1] = (i & 2) ? mins[1] : maxs[1];
1246 v[2] = (i & 4) ? mins[2] : maxs[2];
1248 GL_TransformToScreen(v, v2);
1249 //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]);
1268 // clipped by nearclip plane
1269 // this is nasty and crude...
1270 // create viewspace bbox
1271 for (i = 0;i < 8;i++)
1273 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1274 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1275 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1276 v2[0] = -DotProduct(v, r_viewleft);
1277 v2[1] = DotProduct(v, r_viewup);
1278 v2[2] = DotProduct(v, r_viewforward);
1281 if (smins[0] > v2[0]) smins[0] = v2[0];
1282 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1283 if (smins[1] > v2[1]) smins[1] = v2[1];
1284 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1285 if (smins[2] > v2[2]) smins[2] = v2[2];
1286 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1290 smins[0] = smaxs[0] = v2[0];
1291 smins[1] = smaxs[1] = v2[1];
1292 smins[2] = smaxs[2] = v2[2];
1295 // now we have a bbox in viewspace
1296 // clip it to the view plane
1299 // return true if that culled the box
1300 if (smins[2] >= smaxs[2])
1302 // ok some of it is infront of the view, transform each corner back to
1303 // worldspace and then to screenspace and make screen rect
1304 // initialize these variables just to avoid compiler warnings
1305 x1 = y1 = x2 = y2 = 0;
1306 for (i = 0;i < 8;i++)
1308 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1309 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1310 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1311 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1312 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1313 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1315 GL_TransformToScreen(v, v2);
1316 //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]);
1333 // this code doesn't handle boxes with any points behind view properly
1334 x1 = 1000;x2 = -1000;
1335 y1 = 1000;y2 = -1000;
1336 for (i = 0;i < 8;i++)
1338 v[0] = (i & 1) ? mins[0] : maxs[0];
1339 v[1] = (i & 2) ? mins[1] : maxs[1];
1340 v[2] = (i & 4) ? mins[2] : maxs[2];
1342 GL_TransformToScreen(v, v2);
1343 //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]);
1361 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1362 if (ix1 < r_view_x) ix1 = r_view_x;
1363 if (iy1 < r_view_y) iy1 = r_view_y;
1364 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1365 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1366 if (ix2 <= ix1 || iy2 <= iy1)
1368 // set up the scissor rectangle
1369 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1370 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1371 //qglEnable(GL_SCISSOR_TEST);
1376 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1378 float *color4f = varray_color4f;
1379 float dist, dot, intensity, v[3], n[3];
1380 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1382 Matrix4x4_Transform(m, vertex3f, v);
1383 if ((dist = DotProduct(v, v)) < 1)
1385 Matrix4x4_Transform3x3(m, normal3f, n);
1386 if ((dot = DotProduct(n, v)) > 0)
1389 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1390 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1391 VectorScale(lightcolor, intensity, color4f);
1396 VectorClear(color4f);
1402 VectorClear(color4f);
1408 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1410 float *color4f = varray_color4f;
1411 float dist, dot, intensity, v[3], n[3];
1412 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1414 Matrix4x4_Transform(m, vertex3f, v);
1415 if ((dist = fabs(v[2])) < 1)
1417 Matrix4x4_Transform3x3(m, normal3f, n);
1418 if ((dot = DotProduct(n, v)) > 0)
1420 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1421 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1422 VectorScale(lightcolor, intensity, color4f);
1427 VectorClear(color4f);
1433 VectorClear(color4f);
1439 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1441 float *color4f = varray_color4f;
1442 float dot, intensity, v[3], n[3];
1443 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1445 Matrix4x4_Transform(m, vertex3f, v);
1446 Matrix4x4_Transform3x3(m, normal3f, n);
1447 if ((dot = DotProduct(n, v)) > 0)
1449 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1450 VectorScale(lightcolor, intensity, color4f);
1455 VectorClear(color4f);
1461 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1463 float *color4f = varray_color4f;
1464 float dist, intensity, v[3];
1465 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1467 Matrix4x4_Transform(m, vertex3f, v);
1468 if ((dist = DotProduct(v, v)) < 1)
1471 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1472 VectorScale(lightcolor, intensity, color4f);
1477 VectorClear(color4f);
1483 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1485 float *color4f = varray_color4f;
1486 float dist, intensity, v[3];
1487 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1489 Matrix4x4_Transform(m, vertex3f, v);
1490 if ((dist = fabs(v[2])) < 1)
1492 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1493 VectorScale(lightcolor, intensity, color4f);
1498 VectorClear(color4f);
1504 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1505 #define USETEXMATRIX
1507 #ifndef USETEXMATRIX
1508 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1509 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1510 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1514 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1515 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1516 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1523 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1527 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1528 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1536 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)
1540 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1542 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1543 // the cubemap normalizes this for us
1544 out3f[0] = DotProduct(svector3f, lightdir);
1545 out3f[1] = DotProduct(tvector3f, lightdir);
1546 out3f[2] = DotProduct(normal3f, lightdir);
1550 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)
1553 float lightdir[3], eyedir[3], halfdir[3];
1554 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1556 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1557 VectorNormalizeFast(lightdir);
1558 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1559 VectorNormalizeFast(eyedir);
1560 VectorAdd(lightdir, eyedir, halfdir);
1561 // the cubemap normalizes this for us
1562 out3f[0] = DotProduct(svector3f, halfdir);
1563 out3f[1] = DotProduct(tvector3f, halfdir);
1564 out3f[2] = DotProduct(normal3f, halfdir);
1568 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)
1571 float color[3], color2[3], colorscale;
1573 // FIXME: support EF_NODEPTHTEST
1574 GL_DepthMask(false);
1577 bumptexture = r_shadow_blankbumptexture;
1578 specularscale *= r_shadow_glossintensity.value;
1581 if (r_shadow_gloss.integer >= 2)
1583 glosstexture = r_shadow_blankglosstexture;
1584 specularscale *= r_shadow_gloss2intensity.value;
1588 glosstexture = r_shadow_blankblacktexture;
1592 if (r_shadow_gloss.integer < 1)
1595 lightcubemap = r_shadow_blankwhitecubetexture;
1596 if (ambientscale + diffusescale + specularscale < 0.01)
1598 if (r_shadow_glsl.integer && r_shadow_program_light[0])
1600 unsigned int perm, prog;
1601 // GLSL shader path (GFFX5200, Radeon 9500)
1602 memset(&m, 0, sizeof(m));
1603 m.pointer_vertex = vertex3f;
1604 m.pointer_texcoord[0] = texcoord2f;
1605 m.pointer_texcoord3f[1] = svector3f;
1606 m.pointer_texcoord3f[2] = tvector3f;
1607 m.pointer_texcoord3f[3] = normal3f;
1608 m.tex[0] = R_GetTexture(bumptexture);
1609 m.tex[1] = R_GetTexture(basetexture);
1610 m.tex[2] = R_GetTexture(glosstexture);
1611 m.texcubemap[3] = R_GetTexture(lightcubemap);
1612 // TODO: support fog (after renderer is converted to texture fog)
1613 m.tex[4] = R_GetTexture(r_shadow_blankwhitetexture);
1614 m.texmatrix[3] = *matrix_modeltolight;
1616 GL_BlendFunc(GL_ONE, GL_ONE);
1617 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1621 perm |= SHADERPERMUTATION_SPECULAR;
1623 // perm |= SHADERPERMUTATION_FOG;
1625 perm |= SHADERPERMUTATION_CUBEFILTER;
1626 if (r_shadow_glsl_offsetmapping.integer)
1627 perm |= SHADERPERMUTATION_OFFSETMAPPING;
1628 prog = r_shadow_program_light[perm];
1629 qglUseProgramObjectARB(r_shadow_program_light[perm]);
1630 // TODO: support fog (after renderer is converted to texture fog)
1631 if (perm & SHADERPERMUTATION_FOG)
1632 qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);
1633 qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);
1634 qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);
1635 if (perm & SHADERPERMUTATION_SPECULAR)
1637 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);
1638 qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);
1640 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolor[0], lightcolor[1], lightcolor[2]);
1641 qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);
1642 if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
1643 qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);
1644 if (perm & SHADERPERMUTATION_OFFSETMAPPING)
1646 // these are * 0.25 because the offsetmapping shader does the process 4 times
1647 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value * 0.25);
1648 qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value * 0.25);
1651 GL_LockArrays(0, numverts);
1652 R_Mesh_Draw(numverts, numtriangles, elements);
1654 c_rt_lighttris += numtriangles;
1655 GL_LockArrays(0, 0);
1656 qglUseProgramObjectARB(0);
1658 else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1661 bumptexture = r_shadow_blankbumptexture;
1663 glosstexture = r_shadow_blankglosstexture;
1667 colorscale = ambientscale;
1668 // colorscale accounts for how much we multiply the brightness
1671 // mult is how many times the final pass of the lighting will be
1672 // performed to get more brightness than otherwise possible.
1674 // Limit mult to 64 for sanity sake.
1675 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1677 // 3 3D combine path (Geforce3, Radeon 8500)
1678 memset(&m, 0, sizeof(m));
1679 m.pointer_vertex = vertex3f;
1680 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1682 m.pointer_texcoord3f[0] = vertex3f;
1683 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1685 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1686 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1688 m.tex[1] = R_GetTexture(basetexture);
1689 m.pointer_texcoord[1] = texcoord2f;
1690 m.texcubemap[2] = R_GetTexture(lightcubemap);
1692 m.pointer_texcoord3f[2] = vertex3f;
1693 m.texmatrix[2] = *matrix_modeltolight;
1695 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1696 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1698 GL_BlendFunc(GL_ONE, GL_ONE);
1700 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1702 // 2 3D combine path (Geforce3, original Radeon)
1703 memset(&m, 0, sizeof(m));
1704 m.pointer_vertex = vertex3f;
1705 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1707 m.pointer_texcoord3f[0] = vertex3f;
1708 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1710 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1711 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1713 m.tex[1] = R_GetTexture(basetexture);
1714 m.pointer_texcoord[1] = texcoord2f;
1715 GL_BlendFunc(GL_ONE, GL_ONE);
1717 else if (r_textureunits.integer >= 4 && lightcubemap)
1719 // 4 2D combine path (Geforce3, Radeon 8500)
1720 memset(&m, 0, sizeof(m));
1721 m.pointer_vertex = vertex3f;
1722 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1724 m.pointer_texcoord3f[0] = vertex3f;
1725 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1727 m.pointer_texcoord[0] = varray_texcoord2f[0];
1728 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1730 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1732 m.pointer_texcoord3f[1] = vertex3f;
1733 m.texmatrix[1] = *matrix_modeltoattenuationz;
1735 m.pointer_texcoord[1] = varray_texcoord2f[1];
1736 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1738 m.tex[2] = R_GetTexture(basetexture);
1739 m.pointer_texcoord[2] = texcoord2f;
1742 m.texcubemap[3] = R_GetTexture(lightcubemap);
1744 m.pointer_texcoord3f[3] = vertex3f;
1745 m.texmatrix[3] = *matrix_modeltolight;
1747 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1748 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1751 GL_BlendFunc(GL_ONE, GL_ONE);
1753 else if (r_textureunits.integer >= 3 && !lightcubemap)
1755 // 3 2D combine path (Geforce3, original Radeon)
1756 memset(&m, 0, sizeof(m));
1757 m.pointer_vertex = vertex3f;
1758 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1760 m.pointer_texcoord3f[0] = vertex3f;
1761 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1763 m.pointer_texcoord[0] = varray_texcoord2f[0];
1764 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1766 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1768 m.pointer_texcoord3f[1] = vertex3f;
1769 m.texmatrix[1] = *matrix_modeltoattenuationz;
1771 m.pointer_texcoord[1] = varray_texcoord2f[1];
1772 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1774 m.tex[2] = R_GetTexture(basetexture);
1775 m.pointer_texcoord[2] = texcoord2f;
1776 GL_BlendFunc(GL_ONE, GL_ONE);
1780 // 2/2/2 2D combine path (any dot3 card)
1781 memset(&m, 0, sizeof(m));
1782 m.pointer_vertex = vertex3f;
1783 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1785 m.pointer_texcoord3f[0] = vertex3f;
1786 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1788 m.pointer_texcoord[0] = varray_texcoord2f[0];
1789 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1791 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1793 m.pointer_texcoord3f[1] = vertex3f;
1794 m.texmatrix[1] = *matrix_modeltoattenuationz;
1796 m.pointer_texcoord[1] = varray_texcoord2f[1];
1797 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1800 GL_ColorMask(0,0,0,1);
1801 GL_BlendFunc(GL_ONE, GL_ZERO);
1802 GL_LockArrays(0, numverts);
1803 R_Mesh_Draw(numverts, numtriangles, elements);
1804 GL_LockArrays(0, 0);
1806 c_rt_lighttris += numtriangles;
1808 memset(&m, 0, sizeof(m));
1809 m.pointer_vertex = vertex3f;
1810 m.tex[0] = R_GetTexture(basetexture);
1811 m.pointer_texcoord[0] = texcoord2f;
1814 m.texcubemap[1] = R_GetTexture(lightcubemap);
1816 m.pointer_texcoord3f[1] = vertex3f;
1817 m.texmatrix[1] = *matrix_modeltolight;
1819 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1820 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1823 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1825 // this final code is shared
1827 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1828 VectorScale(lightcolor, colorscale, color2);
1829 GL_LockArrays(0, numverts);
1830 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1832 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1833 R_Mesh_Draw(numverts, numtriangles, elements);
1835 c_rt_lighttris += numtriangles;
1837 GL_LockArrays(0, 0);
1842 colorscale = diffusescale;
1843 // colorscale accounts for how much we multiply the brightness
1846 // mult is how many times the final pass of the lighting will be
1847 // performed to get more brightness than otherwise possible.
1849 // Limit mult to 64 for sanity sake.
1850 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1852 // 3/2 3D combine path (Geforce3, Radeon 8500)
1853 memset(&m, 0, sizeof(m));
1854 m.pointer_vertex = vertex3f;
1855 m.tex[0] = R_GetTexture(bumptexture);
1856 m.texcombinergb[0] = GL_REPLACE;
1857 m.pointer_texcoord[0] = texcoord2f;
1858 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1859 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1860 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1861 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1862 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1864 m.pointer_texcoord3f[2] = vertex3f;
1865 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1867 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1868 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1871 GL_ColorMask(0,0,0,1);
1872 GL_BlendFunc(GL_ONE, GL_ZERO);
1873 GL_LockArrays(0, numverts);
1874 R_Mesh_Draw(numverts, numtriangles, elements);
1875 GL_LockArrays(0, 0);
1877 c_rt_lighttris += numtriangles;
1879 memset(&m, 0, sizeof(m));
1880 m.pointer_vertex = vertex3f;
1881 m.tex[0] = R_GetTexture(basetexture);
1882 m.pointer_texcoord[0] = texcoord2f;
1885 m.texcubemap[1] = R_GetTexture(lightcubemap);
1887 m.pointer_texcoord3f[1] = vertex3f;
1888 m.texmatrix[1] = *matrix_modeltolight;
1890 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1891 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1894 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1896 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1898 // 1/2/2 3D combine path (original Radeon)
1899 memset(&m, 0, sizeof(m));
1900 m.pointer_vertex = vertex3f;
1901 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1903 m.pointer_texcoord3f[0] = vertex3f;
1904 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1906 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1907 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1910 GL_ColorMask(0,0,0,1);
1911 GL_BlendFunc(GL_ONE, GL_ZERO);
1912 GL_LockArrays(0, numverts);
1913 R_Mesh_Draw(numverts, numtriangles, elements);
1914 GL_LockArrays(0, 0);
1916 c_rt_lighttris += numtriangles;
1918 memset(&m, 0, sizeof(m));
1919 m.pointer_vertex = vertex3f;
1920 m.tex[0] = R_GetTexture(bumptexture);
1921 m.texcombinergb[0] = GL_REPLACE;
1922 m.pointer_texcoord[0] = texcoord2f;
1923 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1924 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1925 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1926 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1928 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1929 GL_LockArrays(0, numverts);
1930 R_Mesh_Draw(numverts, numtriangles, elements);
1931 GL_LockArrays(0, 0);
1933 c_rt_lighttris += numtriangles;
1935 memset(&m, 0, sizeof(m));
1936 m.pointer_vertex = vertex3f;
1937 m.tex[0] = R_GetTexture(basetexture);
1938 m.pointer_texcoord[0] = texcoord2f;
1941 m.texcubemap[1] = R_GetTexture(lightcubemap);
1943 m.pointer_texcoord3f[1] = vertex3f;
1944 m.texmatrix[1] = *matrix_modeltolight;
1946 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1947 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1950 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1952 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1954 // 2/2 3D combine path (original Radeon)
1955 memset(&m, 0, sizeof(m));
1956 m.pointer_vertex = vertex3f;
1957 m.tex[0] = R_GetTexture(bumptexture);
1958 m.texcombinergb[0] = GL_REPLACE;
1959 m.pointer_texcoord[0] = texcoord2f;
1960 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1961 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1962 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1963 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1965 GL_ColorMask(0,0,0,1);
1966 GL_BlendFunc(GL_ONE, GL_ZERO);
1967 GL_LockArrays(0, numverts);
1968 R_Mesh_Draw(numverts, numtriangles, elements);
1969 GL_LockArrays(0, 0);
1971 c_rt_lighttris += numtriangles;
1973 memset(&m, 0, sizeof(m));
1974 m.pointer_vertex = vertex3f;
1975 m.tex[0] = R_GetTexture(basetexture);
1976 m.pointer_texcoord[0] = texcoord2f;
1977 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1979 m.pointer_texcoord3f[1] = vertex3f;
1980 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1982 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1983 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1985 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1987 else if (r_textureunits.integer >= 4)
1989 // 4/2 2D combine path (Geforce3, Radeon 8500)
1990 memset(&m, 0, sizeof(m));
1991 m.pointer_vertex = vertex3f;
1992 m.tex[0] = R_GetTexture(bumptexture);
1993 m.texcombinergb[0] = GL_REPLACE;
1994 m.pointer_texcoord[0] = texcoord2f;
1995 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1996 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1997 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1998 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1999 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2001 m.pointer_texcoord3f[2] = vertex3f;
2002 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
2004 m.pointer_texcoord[2] = varray_texcoord2f[2];
2005 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
2007 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2009 m.pointer_texcoord3f[3] = vertex3f;
2010 m.texmatrix[3] = *matrix_modeltoattenuationz;
2012 m.pointer_texcoord[3] = varray_texcoord2f[3];
2013 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
2016 GL_ColorMask(0,0,0,1);
2017 GL_BlendFunc(GL_ONE, GL_ZERO);
2018 GL_LockArrays(0, numverts);
2019 R_Mesh_Draw(numverts, numtriangles, elements);
2020 GL_LockArrays(0, 0);
2022 c_rt_lighttris += numtriangles;
2024 memset(&m, 0, sizeof(m));
2025 m.pointer_vertex = vertex3f;
2026 m.tex[0] = R_GetTexture(basetexture);
2027 m.pointer_texcoord[0] = texcoord2f;
2030 m.texcubemap[1] = R_GetTexture(lightcubemap);
2032 m.pointer_texcoord3f[1] = vertex3f;
2033 m.texmatrix[1] = *matrix_modeltolight;
2035 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2036 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2039 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2043 // 2/2/2 2D combine path (any dot3 card)
2044 memset(&m, 0, sizeof(m));
2045 m.pointer_vertex = vertex3f;
2046 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2048 m.pointer_texcoord3f[0] = vertex3f;
2049 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2051 m.pointer_texcoord[0] = varray_texcoord2f[0];
2052 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2054 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2056 m.pointer_texcoord3f[1] = vertex3f;
2057 m.texmatrix[1] = *matrix_modeltoattenuationz;
2059 m.pointer_texcoord[1] = varray_texcoord2f[1];
2060 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2063 GL_ColorMask(0,0,0,1);
2064 GL_BlendFunc(GL_ONE, GL_ZERO);
2065 GL_LockArrays(0, numverts);
2066 R_Mesh_Draw(numverts, numtriangles, elements);
2067 GL_LockArrays(0, 0);
2069 c_rt_lighttris += numtriangles;
2071 memset(&m, 0, sizeof(m));
2072 m.pointer_vertex = vertex3f;
2073 m.tex[0] = R_GetTexture(bumptexture);
2074 m.texcombinergb[0] = GL_REPLACE;
2075 m.pointer_texcoord[0] = texcoord2f;
2076 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2077 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2078 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2079 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
2081 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2082 GL_LockArrays(0, numverts);
2083 R_Mesh_Draw(numverts, numtriangles, elements);
2084 GL_LockArrays(0, 0);
2086 c_rt_lighttris += numtriangles;
2088 memset(&m, 0, sizeof(m));
2089 m.pointer_vertex = vertex3f;
2090 m.tex[0] = R_GetTexture(basetexture);
2091 m.pointer_texcoord[0] = texcoord2f;
2094 m.texcubemap[1] = R_GetTexture(lightcubemap);
2096 m.pointer_texcoord3f[1] = vertex3f;
2097 m.texmatrix[1] = *matrix_modeltolight;
2099 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2100 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2103 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2105 // this final code is shared
2107 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2108 VectorScale(lightcolor, colorscale, color2);
2109 GL_LockArrays(0, numverts);
2110 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2112 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2113 R_Mesh_Draw(numverts, numtriangles, elements);
2115 c_rt_lighttris += numtriangles;
2117 GL_LockArrays(0, 0);
2119 if (specularscale && glosstexture != r_shadow_blankblacktexture)
2121 // FIXME: detect blendsquare!
2122 //if (gl_support_blendsquare)
2124 colorscale = specularscale;
2126 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2128 // 2/0/0/1/2 3D combine blendsquare path
2129 memset(&m, 0, sizeof(m));
2130 m.pointer_vertex = vertex3f;
2131 m.tex[0] = R_GetTexture(bumptexture);
2132 m.pointer_texcoord[0] = texcoord2f;
2133 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2134 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2135 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2136 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2138 GL_ColorMask(0,0,0,1);
2139 // this squares the result
2140 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2141 GL_LockArrays(0, numverts);
2142 R_Mesh_Draw(numverts, numtriangles, elements);
2143 GL_LockArrays(0, 0);
2145 c_rt_lighttris += numtriangles;
2147 memset(&m, 0, sizeof(m));
2148 m.pointer_vertex = vertex3f;
2150 GL_LockArrays(0, numverts);
2151 // square alpha in framebuffer a few times to make it shiny
2152 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2153 // these comments are a test run through this math for intensity 0.5
2154 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2155 // 0.25 * 0.25 = 0.0625 (this is another pass)
2156 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2157 R_Mesh_Draw(numverts, numtriangles, elements);
2159 c_rt_lighttris += numtriangles;
2160 R_Mesh_Draw(numverts, numtriangles, elements);
2162 c_rt_lighttris += numtriangles;
2163 GL_LockArrays(0, 0);
2165 memset(&m, 0, sizeof(m));
2166 m.pointer_vertex = vertex3f;
2167 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2169 m.pointer_texcoord3f[0] = vertex3f;
2170 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2172 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
2173 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2176 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2177 GL_LockArrays(0, numverts);
2178 R_Mesh_Draw(numverts, numtriangles, elements);
2179 GL_LockArrays(0, 0);
2181 c_rt_lighttris += numtriangles;
2183 memset(&m, 0, sizeof(m));
2184 m.pointer_vertex = vertex3f;
2185 m.tex[0] = R_GetTexture(glosstexture);
2186 m.pointer_texcoord[0] = texcoord2f;
2189 m.texcubemap[1] = R_GetTexture(lightcubemap);
2191 m.pointer_texcoord3f[1] = vertex3f;
2192 m.texmatrix[1] = *matrix_modeltolight;
2194 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2195 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2198 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2200 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
2202 // 2/0/0/2 3D combine blendsquare path
2203 memset(&m, 0, sizeof(m));
2204 m.pointer_vertex = vertex3f;
2205 m.tex[0] = R_GetTexture(bumptexture);
2206 m.pointer_texcoord[0] = texcoord2f;
2207 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2208 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2209 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2210 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2212 GL_ColorMask(0,0,0,1);
2213 // this squares the result
2214 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2215 GL_LockArrays(0, numverts);
2216 R_Mesh_Draw(numverts, numtriangles, elements);
2217 GL_LockArrays(0, 0);
2219 c_rt_lighttris += numtriangles;
2221 memset(&m, 0, sizeof(m));
2222 m.pointer_vertex = vertex3f;
2224 GL_LockArrays(0, numverts);
2225 // square alpha in framebuffer a few times to make it shiny
2226 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2227 // these comments are a test run through this math for intensity 0.5
2228 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2229 // 0.25 * 0.25 = 0.0625 (this is another pass)
2230 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2231 R_Mesh_Draw(numverts, numtriangles, elements);
2233 c_rt_lighttris += numtriangles;
2234 R_Mesh_Draw(numverts, numtriangles, elements);
2236 c_rt_lighttris += numtriangles;
2237 GL_LockArrays(0, 0);
2239 memset(&m, 0, sizeof(m));
2240 m.pointer_vertex = vertex3f;
2241 m.tex[0] = R_GetTexture(glosstexture);
2242 m.pointer_texcoord[0] = texcoord2f;
2243 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2245 m.pointer_texcoord3f[1] = vertex3f;
2246 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2248 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2249 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2251 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2255 // 2/0/0/2/2 2D combine blendsquare path
2256 memset(&m, 0, sizeof(m));
2257 m.pointer_vertex = vertex3f;
2258 m.tex[0] = R_GetTexture(bumptexture);
2259 m.pointer_texcoord[0] = texcoord2f;
2260 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
2261 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2262 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2263 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
2265 GL_ColorMask(0,0,0,1);
2266 // this squares the result
2267 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2268 GL_LockArrays(0, numverts);
2269 R_Mesh_Draw(numverts, numtriangles, elements);
2270 GL_LockArrays(0, 0);
2272 c_rt_lighttris += numtriangles;
2274 memset(&m, 0, sizeof(m));
2275 m.pointer_vertex = vertex3f;
2277 GL_LockArrays(0, numverts);
2278 // square alpha in framebuffer a few times to make it shiny
2279 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2280 // these comments are a test run through this math for intensity 0.5
2281 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
2282 // 0.25 * 0.25 = 0.0625 (this is another pass)
2283 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
2284 R_Mesh_Draw(numverts, numtriangles, elements);
2286 c_rt_lighttris += numtriangles;
2287 R_Mesh_Draw(numverts, numtriangles, elements);
2289 c_rt_lighttris += numtriangles;
2290 GL_LockArrays(0, 0);
2292 memset(&m, 0, sizeof(m));
2293 m.pointer_vertex = vertex3f;
2294 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2296 m.pointer_texcoord3f[0] = vertex3f;
2297 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2299 m.pointer_texcoord[0] = varray_texcoord2f[0];
2300 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2302 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2304 m.pointer_texcoord3f[1] = vertex3f;
2305 m.texmatrix[1] = *matrix_modeltoattenuationz;
2307 m.pointer_texcoord[1] = varray_texcoord2f[1];
2308 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2311 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2312 GL_LockArrays(0, numverts);
2313 R_Mesh_Draw(numverts, numtriangles, elements);
2314 GL_LockArrays(0, 0);
2316 c_rt_lighttris += numtriangles;
2318 memset(&m, 0, sizeof(m));
2319 m.pointer_vertex = vertex3f;
2320 m.tex[0] = R_GetTexture(glosstexture);
2321 m.pointer_texcoord[0] = texcoord2f;
2324 m.texcubemap[1] = R_GetTexture(lightcubemap);
2326 m.pointer_texcoord3f[1] = vertex3f;
2327 m.texmatrix[1] = *matrix_modeltolight;
2329 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2330 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2333 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2336 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2337 VectorScale(lightcolor, colorscale, color2);
2338 GL_LockArrays(0, numverts);
2339 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2341 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2342 R_Mesh_Draw(numverts, numtriangles, elements);
2344 c_rt_lighttris += numtriangles;
2346 GL_LockArrays(0, 0);
2354 GL_BlendFunc(GL_ONE, GL_ONE);
2355 VectorScale(lightcolor, ambientscale, color2);
2356 memset(&m, 0, sizeof(m));
2357 m.pointer_vertex = vertex3f;
2358 m.tex[0] = R_GetTexture(basetexture);
2359 m.pointer_texcoord[0] = texcoord2f;
2360 if (r_textureunits.integer >= 2)
2363 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2365 m.pointer_texcoord3f[1] = vertex3f;
2366 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2368 m.pointer_texcoord[1] = varray_texcoord2f[1];
2369 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2371 if (r_textureunits.integer >= 3)
2373 // Geforce3/Radeon class but not using dot3
2374 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2376 m.pointer_texcoord3f[2] = vertex3f;
2377 m.texmatrix[2] = *matrix_modeltoattenuationz;
2379 m.pointer_texcoord[2] = varray_texcoord2f[2];
2380 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2384 if (r_textureunits.integer >= 3)
2385 m.pointer_color = NULL;
2387 m.pointer_color = varray_color4f;
2389 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2391 color[0] = bound(0, color2[0], 1);
2392 color[1] = bound(0, color2[1], 1);
2393 color[2] = bound(0, color2[2], 1);
2394 if (r_textureunits.integer >= 3)
2395 GL_Color(color[0], color[1], color[2], 1);
2396 else if (r_textureunits.integer >= 2)
2397 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2399 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2400 GL_LockArrays(0, numverts);
2401 R_Mesh_Draw(numverts, numtriangles, elements);
2402 GL_LockArrays(0, 0);
2404 c_rt_lighttris += numtriangles;
2409 GL_BlendFunc(GL_ONE, GL_ONE);
2410 VectorScale(lightcolor, diffusescale, color2);
2411 memset(&m, 0, sizeof(m));
2412 m.pointer_vertex = vertex3f;
2413 m.pointer_color = varray_color4f;
2414 m.tex[0] = R_GetTexture(basetexture);
2415 m.pointer_texcoord[0] = texcoord2f;
2416 if (r_textureunits.integer >= 2)
2419 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2421 m.pointer_texcoord3f[1] = vertex3f;
2422 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2424 m.pointer_texcoord[1] = varray_texcoord2f[1];
2425 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2427 if (r_textureunits.integer >= 3)
2429 // Geforce3/Radeon class but not using dot3
2430 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2432 m.pointer_texcoord3f[2] = vertex3f;
2433 m.texmatrix[2] = *matrix_modeltoattenuationz;
2435 m.pointer_texcoord[2] = varray_texcoord2f[2];
2436 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2441 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2443 color[0] = bound(0, color2[0], 1);
2444 color[1] = bound(0, color2[1], 1);
2445 color[2] = bound(0, color2[2], 1);
2446 if (r_textureunits.integer >= 3)
2447 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2448 else if (r_textureunits.integer >= 2)
2449 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2451 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2452 GL_LockArrays(0, numverts);
2453 R_Mesh_Draw(numverts, numtriangles, elements);
2454 GL_LockArrays(0, 0);
2456 c_rt_lighttris += numtriangles;
2462 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2466 R_RTLight_Uncompile(rtlight);
2467 memset(rtlight, 0, sizeof(*rtlight));
2469 VectorCopy(light->origin, rtlight->shadoworigin);
2470 VectorCopy(light->color, rtlight->color);
2471 rtlight->radius = light->radius;
2472 //rtlight->cullradius = rtlight->radius;
2473 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2474 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2475 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2476 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2477 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2478 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2479 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2480 rtlight->cubemapname[0] = 0;
2481 if (light->cubemapname[0])
2482 strcpy(rtlight->cubemapname, light->cubemapname);
2483 else if (light->cubemapnum > 0)
2484 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2485 rtlight->shadow = light->shadow;
2486 rtlight->corona = light->corona;
2487 rtlight->style = light->style;
2488 rtlight->isstatic = isstatic;
2489 rtlight->coronasizescale = light->coronasizescale;
2490 rtlight->ambientscale = light->ambientscale;
2491 rtlight->diffusescale = light->diffusescale;
2492 rtlight->specularscale = light->specularscale;
2493 rtlight->flags = light->flags;
2494 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2495 // ConcatScale won't work here because this needs to scale rotate and
2496 // translate, not just rotate
2497 scale = 1.0f / rtlight->radius;
2498 for (k = 0;k < 3;k++)
2499 for (j = 0;j < 4;j++)
2500 rtlight->matrix_worldtolight.m[k][j] *= scale;
2501 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2502 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2504 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2505 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2506 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2507 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2510 // compiles rtlight geometry
2511 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2512 void R_RTLight_Compile(rtlight_t *rtlight)
2514 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2515 entity_render_t *ent = &cl_entities[0].render;
2516 model_t *model = ent->model;
2518 // compile the light
2519 rtlight->compiled = true;
2520 rtlight->static_numclusters = 0;
2521 rtlight->static_numclusterpvsbytes = 0;
2522 rtlight->static_clusterlist = NULL;
2523 rtlight->static_clusterpvs = NULL;
2524 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2525 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2526 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2527 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2528 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2529 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2531 if (model && model->GetLightInfo)
2533 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2534 r_shadow_compilingrtlight = rtlight;
2535 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2536 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2537 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);
2538 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2539 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2542 rtlight->static_numclusters = numclusters;
2543 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2544 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2545 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2547 if (model->DrawShadowVolume && rtlight->shadow)
2549 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2550 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2551 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2553 if (model->DrawLight)
2555 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2556 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);
2557 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2559 // switch back to rendering when DrawShadowVolume or DrawLight is called
2560 r_shadow_compilingrtlight = NULL;
2564 // use smallest available cullradius - box radius or light radius
2565 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2566 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2570 if (rtlight->static_meshchain_shadow)
2573 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2576 shadowtris += mesh->numtriangles;
2582 if (rtlight->static_meshchain_light)
2585 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2588 lighttris += mesh->numtriangles;
2592 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);
2595 void R_RTLight_Uncompile(rtlight_t *rtlight)
2597 if (rtlight->compiled)
2599 if (rtlight->static_meshchain_shadow)
2600 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2601 rtlight->static_meshchain_shadow = NULL;
2602 if (rtlight->static_meshchain_light)
2603 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2604 rtlight->static_meshchain_light = NULL;
2605 if (rtlight->static_clusterlist)
2606 Mem_Free(rtlight->static_clusterlist);
2607 rtlight->static_clusterlist = NULL;
2608 if (rtlight->static_clusterpvs)
2609 Mem_Free(rtlight->static_clusterpvs);
2610 rtlight->static_clusterpvs = NULL;
2611 rtlight->static_numclusters = 0;
2612 rtlight->static_numclusterpvsbytes = 0;
2613 rtlight->compiled = false;
2617 void R_Shadow_UncompileWorldLights(void)
2620 for (light = r_shadow_worldlightchain;light;light = light->next)
2621 R_RTLight_Uncompile(&light->rtlight);
2624 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2626 int i, shadow, usestencil;
2627 entity_render_t *ent;
2629 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2630 rtexture_t *cubemaptexture;
2631 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2632 int numclusters, numsurfaces;
2633 int *clusterlist, *surfacelist;
2635 vec3_t cullmins, cullmaxs;
2639 // skip lights that don't light (corona only lights)
2640 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2643 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2644 VectorScale(rtlight->color, f, lightcolor);
2645 if (VectorLength2(lightcolor) < 0.01)
2648 if (rtlight->selected)
2650 f = 2 + sin(realtime * M_PI * 4.0);
2651 VectorScale(lightcolor, f, lightcolor);
2655 // loading is done before visibility checks because loading should happen
2656 // all at once at the start of a level, not when it stalls gameplay.
2657 // (especially important to benchmarks)
2658 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2659 R_RTLight_Compile(rtlight);
2660 if (rtlight->cubemapname[0])
2661 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2663 cubemaptexture = NULL;
2665 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2666 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2667 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2668 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2669 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2670 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2671 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2678 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2680 // compiled light, world available and can receive realtime lighting
2681 // retrieve cluster information
2682 numclusters = rtlight->static_numclusters;
2683 clusterlist = rtlight->static_clusterlist;
2684 clusterpvs = rtlight->static_clusterpvs;
2685 VectorCopy(rtlight->cullmins, cullmins);
2686 VectorCopy(rtlight->cullmaxs, cullmaxs);
2688 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2690 // dynamic light, world available and can receive realtime lighting
2691 // if the light box is offscreen, skip it right away
2692 if (R_CullBox(cullmins, cullmaxs))
2694 // calculate lit surfaces and clusters
2695 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2696 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2697 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);
2698 clusterlist = r_shadow_buffer_clusterlist;
2699 clusterpvs = r_shadow_buffer_clusterpvs;
2700 surfacelist = r_shadow_buffer_surfacelist;
2702 // if the reduced cluster bounds are offscreen, skip it
2703 if (R_CullBox(cullmins, cullmaxs))
2705 // check if light is illuminating any visible clusters
2708 for (i = 0;i < numclusters;i++)
2709 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2711 if (i == numclusters)
2714 // set up a scissor rectangle for this light
2715 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2718 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2721 if (shadow && (gl_stencil || visiblevolumes))
2723 if (!visiblevolumes)
2725 R_Shadow_Stage_ShadowVolumes();
2728 ent = &cl_entities[0].render;
2729 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2731 memset(&m, 0, sizeof(m));
2732 R_Mesh_Matrix(&ent->matrix);
2733 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2735 m.pointer_vertex = mesh->vertex3f;
2737 GL_LockArrays(0, mesh->numverts);
2738 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2740 // increment stencil if backface is behind depthbuffer
2741 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2742 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2743 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2744 c_rtcached_shadowmeshes++;
2745 c_rtcached_shadowtris += mesh->numtriangles;
2746 // decrement stencil if frontface is behind depthbuffer
2747 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2748 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2750 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2751 c_rtcached_shadowmeshes++;
2752 c_rtcached_shadowtris += mesh->numtriangles;
2753 GL_LockArrays(0, 0);
2756 else if (numsurfaces)
2758 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2759 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2761 if (r_drawentities.integer)
2763 for (i = 0;i < r_refdef.numentities;i++)
2765 ent = r_refdef.entities[i];
2767 if (r_shadow_cull.integer)
2769 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2771 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2774 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2776 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2777 // light emitting entities should not cast their own shadow
2778 if (VectorLength2(relativelightorigin) < 0.1)
2780 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2785 if (!visiblevolumes)
2787 R_Shadow_Stage_Light(usestencil);
2789 ent = &cl_entities[0].render;
2790 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2792 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2793 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2794 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2795 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2796 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2797 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2798 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2799 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2800 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2802 R_Mesh_Matrix(&ent->matrix);
2803 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2804 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);
2807 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2809 if (r_drawentities.integer)
2811 for (i = 0;i < r_refdef.numentities;i++)
2813 ent = r_refdef.entities[i];
2814 // can't draw transparent entity lighting here because
2815 // transparent meshes are deferred for later
2816 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)
2818 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2819 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2820 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2821 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2822 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2823 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2824 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2825 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2826 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);
2833 void R_ShadowVolumeLighting(int visiblevolumes)
2839 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2840 R_Shadow_EditLights_Reload_f();
2844 memset(&m, 0, sizeof(m));
2847 GL_BlendFunc(GL_ONE, GL_ONE);
2848 GL_DepthMask(false);
2849 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2850 qglDisable(GL_CULL_FACE);
2851 GL_Color(0.0, 0.0125, 0.1, 1);
2854 R_Shadow_Stage_Begin();
2855 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2856 if (r_shadow_debuglight.integer >= 0)
2858 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2859 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2860 R_DrawRTLight(&light->rtlight, visiblevolumes);
2863 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2864 if (light->flags & flag)
2865 R_DrawRTLight(&light->rtlight, visiblevolumes);
2867 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2868 R_DrawRTLight(&light->rtlight, visiblevolumes);
2872 qglEnable(GL_CULL_FACE);
2873 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2876 R_Shadow_Stage_End();
2879 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2880 typedef struct suffixinfo_s
2883 qboolean flipx, flipy, flipdiagonal;
2886 static suffixinfo_t suffix[3][6] =
2889 {"px", false, false, false},
2890 {"nx", false, false, false},
2891 {"py", false, false, false},
2892 {"ny", false, false, false},
2893 {"pz", false, false, false},
2894 {"nz", false, false, false}
2897 {"posx", false, false, false},
2898 {"negx", false, false, false},
2899 {"posy", false, false, false},
2900 {"negy", false, false, false},
2901 {"posz", false, false, false},
2902 {"negz", false, false, false}
2905 {"rt", true, false, true},
2906 {"lf", false, true, true},
2907 {"ft", true, true, false},
2908 {"bk", false, false, false},
2909 {"up", true, false, true},
2910 {"dn", true, false, true}
2914 static int componentorder[4] = {0, 1, 2, 3};
2916 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2918 int i, j, cubemapsize;
2919 qbyte *cubemappixels, *image_rgba;
2920 rtexture_t *cubemaptexture;
2922 // must start 0 so the first loadimagepixels has no requested width/height
2924 cubemappixels = NULL;
2925 cubemaptexture = NULL;
2926 // keep trying different suffix groups (posx, px, rt) until one loads
2927 for (j = 0;j < 3 && !cubemappixels;j++)
2929 // load the 6 images in the suffix group
2930 for (i = 0;i < 6;i++)
2932 // generate an image name based on the base and and suffix
2933 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2935 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2937 // an image loaded, make sure width and height are equal
2938 if (image_width == image_height)
2940 // if this is the first image to load successfully, allocate the cubemap memory
2941 if (!cubemappixels && image_width >= 1)
2943 cubemapsize = image_width;
2944 // note this clears to black, so unavailable sides are black
2945 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2947 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2949 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);
2952 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2954 Mem_Free(image_rgba);
2958 // if a cubemap loaded, upload it
2961 if (!r_shadow_filters_texturepool)
2962 r_shadow_filters_texturepool = R_AllocTexturePool();
2963 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2964 Mem_Free(cubemappixels);
2968 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2969 for (j = 0;j < 3;j++)
2970 for (i = 0;i < 6;i++)
2971 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2972 Con_Print(" and was unable to find any of them.\n");
2974 return cubemaptexture;
2977 rtexture_t *R_Shadow_Cubemap(const char *basename)
2980 for (i = 0;i < numcubemaps;i++)
2981 if (!strcasecmp(cubemaps[i].basename, basename))
2982 return cubemaps[i].texture;
2983 if (i >= MAX_CUBEMAPS)
2986 strcpy(cubemaps[i].basename, basename);
2987 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2988 return cubemaps[i].texture;
2991 void R_Shadow_FreeCubemaps(void)
2994 R_FreeTexturePool(&r_shadow_filters_texturepool);
2997 dlight_t *R_Shadow_NewWorldLight(void)
3000 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
3001 light->next = r_shadow_worldlightchain;
3002 r_shadow_worldlightchain = light;
3006 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)
3008 VectorCopy(origin, light->origin);
3009 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3010 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3011 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3012 light->color[0] = max(color[0], 0);
3013 light->color[1] = max(color[1], 0);
3014 light->color[2] = max(color[2], 0);
3015 light->radius = max(radius, 0);
3016 light->style = style;
3017 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
3019 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3022 light->shadow = shadowenable;
3023 light->corona = corona;
3026 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
3027 light->coronasizescale = coronasizescale;
3028 light->ambientscale = ambientscale;
3029 light->diffusescale = diffusescale;
3030 light->specularscale = specularscale;
3031 light->flags = flags;
3032 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
3034 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
3037 void R_Shadow_FreeWorldLight(dlight_t *light)
3039 dlight_t **lightpointer;
3040 R_RTLight_Uncompile(&light->rtlight);
3041 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3042 if (*lightpointer != light)
3043 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
3044 *lightpointer = light->next;
3048 void R_Shadow_ClearWorldLights(void)
3050 while (r_shadow_worldlightchain)
3051 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3052 r_shadow_selectedlight = NULL;
3053 R_Shadow_FreeCubemaps();
3056 void R_Shadow_SelectLight(dlight_t *light)
3058 if (r_shadow_selectedlight)
3059 r_shadow_selectedlight->selected = false;
3060 r_shadow_selectedlight = light;
3061 if (r_shadow_selectedlight)
3062 r_shadow_selectedlight->selected = true;
3065 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
3067 float scale = r_editlights_cursorgrid.value * 0.5f;
3068 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);
3071 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
3074 const dlight_t *light;
3077 if (light->selected)
3078 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3081 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);
3084 void R_Shadow_DrawLightSprites(void)
3090 for (i = 0;i < 5;i++)
3092 lighttextures[i] = NULL;
3093 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
3094 lighttextures[i] = pic->tex;
3097 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3098 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
3099 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
3102 void R_Shadow_SelectLightInView(void)
3104 float bestrating, rating, temp[3];
3105 dlight_t *best, *light;
3108 for (light = r_shadow_worldlightchain;light;light = light->next)
3110 VectorSubtract(light->origin, r_vieworigin, temp);
3111 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
3114 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3115 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
3117 bestrating = rating;
3122 R_Shadow_SelectLight(best);
3125 void R_Shadow_LoadWorldLights(void)
3127 int n, a, style, shadow, flags;
3128 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
3129 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3130 if (r_refdef.worldmodel == NULL)
3132 Con_Print("No map loaded.\n");
3135 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3136 strlcat (name, ".rtlights", sizeof (name));
3137 lightsstring = FS_LoadFile(name, tempmempool, false);
3147 for (;COM_Parse(t, true) && strcmp(
3148 if (COM_Parse(t, true))
3150 if (com_token[0] == '!')
3153 origin[0] = atof(com_token+1);
3156 origin[0] = atof(com_token);
3161 while (*s && *s != '\n')
3167 // check for modifier flags
3173 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);
3175 flags = LIGHTFLAG_REALTIMEMODE;
3183 coronasizescale = 0.25f;
3185 VectorClear(angles);
3188 if (a < 9 || !strcmp(cubemapname, "\"\""))
3190 // remove quotes on cubemapname
3191 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3193 cubemapname[strlen(cubemapname)-1] = 0;
3194 strcpy(cubemapname, cubemapname + 1);
3199 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);
3202 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
3203 radius *= r_editlights_rtlightssizescale.value;
3204 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3209 Con_Printf("invalid rtlights file \"%s\"\n", name);
3210 Mem_Free(lightsstring);
3214 void R_Shadow_SaveWorldLights(void)
3217 int bufchars, bufmaxchars;
3219 char name[MAX_QPATH];
3221 if (!r_shadow_worldlightchain)
3223 if (r_refdef.worldmodel == NULL)
3225 Con_Print("No map loaded.\n");
3228 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3229 strlcat (name, ".rtlights", sizeof (name));
3230 bufchars = bufmaxchars = 0;
3232 for (light = r_shadow_worldlightchain;light;light = light->next)
3234 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3235 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);
3236 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3237 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]);
3239 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);
3240 if (bufchars + (int) strlen(line) > bufmaxchars)
3242 bufmaxchars = bufchars + strlen(line) + 2048;
3244 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
3248 memcpy(buf, oldbuf, bufchars);
3254 memcpy(buf + bufchars, line, strlen(line));
3255 bufchars += strlen(line);
3259 FS_WriteFile(name, buf, bufchars);
3264 void R_Shadow_LoadLightsFile(void)
3267 char name[MAX_QPATH], *lightsstring, *s, *t;
3268 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3269 if (r_refdef.worldmodel == NULL)
3271 Con_Print("No map loaded.\n");
3274 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3275 strlcat (name, ".lights", sizeof (name));
3276 lightsstring = FS_LoadFile(name, tempmempool, false);
3284 while (*s && *s != '\n')
3289 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);
3293 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);
3296 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3297 radius = bound(15, radius, 4096);
3298 VectorScale(color, (2.0f / (8388608.0f)), color);
3299 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3304 Con_Printf("invalid lights file \"%s\"\n", name);
3305 Mem_Free(lightsstring);
3309 // tyrlite/hmap2 light types in the delay field
3310 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3312 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3314 int entnum, style, islight, skin, pflags, effects, type, n;
3317 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3318 char key[256], value[1024];
3320 if (r_refdef.worldmodel == NULL)
3322 Con_Print("No map loaded.\n");
3325 // try to load a .ent file first
3326 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3327 strlcat (key, ".ent", sizeof (key));
3328 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3329 // and if that is not found, fall back to the bsp file entity string
3331 data = r_refdef.worldmodel->brush.entities;
3334 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3336 type = LIGHTTYPE_MINUSX;
3337 origin[0] = origin[1] = origin[2] = 0;
3338 originhack[0] = originhack[1] = originhack[2] = 0;
3339 angles[0] = angles[1] = angles[2] = 0;
3340 color[0] = color[1] = color[2] = 1;
3341 light[0] = light[1] = light[2] = 1;light[3] = 300;
3342 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3352 if (!COM_ParseToken(&data, false))
3354 if (com_token[0] == '}')
3355 break; // end of entity
3356 if (com_token[0] == '_')
3357 strcpy(key, com_token + 1);
3359 strcpy(key, com_token);
3360 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3361 key[strlen(key)-1] = 0;
3362 if (!COM_ParseToken(&data, false))
3364 strcpy(value, com_token);
3366 // now that we have the key pair worked out...
3367 if (!strcmp("light", key))
3369 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3373 light[0] = vec[0] * (1.0f / 256.0f);
3374 light[1] = vec[0] * (1.0f / 256.0f);
3375 light[2] = vec[0] * (1.0f / 256.0f);
3381 light[0] = vec[0] * (1.0f / 255.0f);
3382 light[1] = vec[1] * (1.0f / 255.0f);
3383 light[2] = vec[2] * (1.0f / 255.0f);
3387 else if (!strcmp("delay", key))
3389 else if (!strcmp("origin", key))
3390 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3391 else if (!strcmp("angle", key))
3392 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3393 else if (!strcmp("angles", key))
3394 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3395 else if (!strcmp("color", key))
3396 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3397 else if (!strcmp("wait", key))
3398 fadescale = atof(value);
3399 else if (!strcmp("classname", key))
3401 if (!strncmp(value, "light", 5))
3404 if (!strcmp(value, "light_fluoro"))
3409 overridecolor[0] = 1;
3410 overridecolor[1] = 1;
3411 overridecolor[2] = 1;
3413 if (!strcmp(value, "light_fluorospark"))
3418 overridecolor[0] = 1;
3419 overridecolor[1] = 1;
3420 overridecolor[2] = 1;
3422 if (!strcmp(value, "light_globe"))
3427 overridecolor[0] = 1;
3428 overridecolor[1] = 0.8;
3429 overridecolor[2] = 0.4;
3431 if (!strcmp(value, "light_flame_large_yellow"))
3436 overridecolor[0] = 1;
3437 overridecolor[1] = 0.5;
3438 overridecolor[2] = 0.1;
3440 if (!strcmp(value, "light_flame_small_yellow"))
3445 overridecolor[0] = 1;
3446 overridecolor[1] = 0.5;
3447 overridecolor[2] = 0.1;
3449 if (!strcmp(value, "light_torch_small_white"))
3454 overridecolor[0] = 1;
3455 overridecolor[1] = 0.5;
3456 overridecolor[2] = 0.1;
3458 if (!strcmp(value, "light_torch_small_walltorch"))
3463 overridecolor[0] = 1;
3464 overridecolor[1] = 0.5;
3465 overridecolor[2] = 0.1;
3469 else if (!strcmp("style", key))
3470 style = atoi(value);
3471 else if (r_refdef.worldmodel->type == mod_brushq3)
3473 if (!strcmp("scale", key))
3474 lightscale = atof(value);
3475 if (!strcmp("fade", key))
3476 fadescale = atof(value);
3478 else if (!strcmp("skin", key))
3479 skin = (int)atof(value);
3480 else if (!strcmp("pflags", key))
3481 pflags = (int)atof(value);
3482 else if (!strcmp("effects", key))
3483 effects = (int)atof(value);
3487 if (lightscale <= 0)
3491 if (color[0] == color[1] && color[0] == color[2])
3493 color[0] *= overridecolor[0];
3494 color[1] *= overridecolor[1];
3495 color[2] *= overridecolor[2];
3497 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3498 color[0] = color[0] * light[0];
3499 color[1] = color[1] * light[1];
3500 color[2] = color[2] * light[2];
3503 case LIGHTTYPE_MINUSX:
3505 case LIGHTTYPE_RECIPX:
3507 VectorScale(color, (1.0f / 16.0f), color);
3509 case LIGHTTYPE_RECIPXX:
3511 VectorScale(color, (1.0f / 16.0f), color);
3514 case LIGHTTYPE_NONE:
3518 case LIGHTTYPE_MINUSXX:
3521 VectorAdd(origin, originhack, origin);
3523 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);
3526 Mem_Free(entfiledata);
3530 void R_Shadow_SetCursorLocationForView(void)
3532 vec_t dist, push, frac;
3533 vec3_t dest, endpos, normal;
3534 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3535 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3538 dist = frac * r_editlights_cursordistance.value;
3539 push = r_editlights_cursorpushback.value;
3543 VectorMA(endpos, push, r_viewforward, endpos);
3544 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3546 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3547 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3548 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3551 void R_Shadow_UpdateWorldLightSelection(void)
3553 if (r_editlights.integer)
3555 R_Shadow_SetCursorLocationForView();
3556 R_Shadow_SelectLightInView();
3557 R_Shadow_DrawLightSprites();
3560 R_Shadow_SelectLight(NULL);
3563 void R_Shadow_EditLights_Clear_f(void)
3565 R_Shadow_ClearWorldLights();
3568 void R_Shadow_EditLights_Reload_f(void)
3570 if (!r_refdef.worldmodel)
3572 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3573 R_Shadow_ClearWorldLights();
3574 R_Shadow_LoadWorldLights();
3575 if (r_shadow_worldlightchain == NULL)
3577 R_Shadow_LoadLightsFile();
3578 if (r_shadow_worldlightchain == NULL)
3579 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3583 void R_Shadow_EditLights_Save_f(void)
3585 if (!r_refdef.worldmodel)
3587 R_Shadow_SaveWorldLights();
3590 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3592 R_Shadow_ClearWorldLights();
3593 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3596 void R_Shadow_EditLights_ImportLightsFile_f(void)
3598 R_Shadow_ClearWorldLights();
3599 R_Shadow_LoadLightsFile();
3602 void R_Shadow_EditLights_Spawn_f(void)
3605 if (!r_editlights.integer)
3607 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3610 if (Cmd_Argc() != 1)
3612 Con_Print("r_editlights_spawn does not take parameters\n");
3615 color[0] = color[1] = color[2] = 1;
3616 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3619 void R_Shadow_EditLights_Edit_f(void)
3621 vec3_t origin, angles, color;
3622 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3623 int style, shadows, flags, normalmode, realtimemode;
3624 char cubemapname[1024];
3625 if (!r_editlights.integer)
3627 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3630 if (!r_shadow_selectedlight)
3632 Con_Print("No selected light.\n");
3635 VectorCopy(r_shadow_selectedlight->origin, origin);
3636 VectorCopy(r_shadow_selectedlight->angles, angles);
3637 VectorCopy(r_shadow_selectedlight->color, color);
3638 radius = r_shadow_selectedlight->radius;
3639 style = r_shadow_selectedlight->style;
3640 if (r_shadow_selectedlight->cubemapname)
3641 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3644 shadows = r_shadow_selectedlight->shadow;
3645 corona = r_shadow_selectedlight->corona;
3646 coronasizescale = r_shadow_selectedlight->coronasizescale;
3647 ambientscale = r_shadow_selectedlight->ambientscale;
3648 diffusescale = r_shadow_selectedlight->diffusescale;
3649 specularscale = r_shadow_selectedlight->specularscale;
3650 flags = r_shadow_selectedlight->flags;
3651 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3652 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3653 if (!strcmp(Cmd_Argv(1), "origin"))
3655 if (Cmd_Argc() != 5)
3657 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3660 origin[0] = atof(Cmd_Argv(2));
3661 origin[1] = atof(Cmd_Argv(3));
3662 origin[2] = atof(Cmd_Argv(4));
3664 else if (!strcmp(Cmd_Argv(1), "originx"))
3666 if (Cmd_Argc() != 3)
3668 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3671 origin[0] = atof(Cmd_Argv(2));
3673 else if (!strcmp(Cmd_Argv(1), "originy"))
3675 if (Cmd_Argc() != 3)
3677 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3680 origin[1] = atof(Cmd_Argv(2));
3682 else if (!strcmp(Cmd_Argv(1), "originz"))
3684 if (Cmd_Argc() != 3)
3686 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3689 origin[2] = atof(Cmd_Argv(2));
3691 else if (!strcmp(Cmd_Argv(1), "move"))
3693 if (Cmd_Argc() != 5)
3695 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3698 origin[0] += atof(Cmd_Argv(2));
3699 origin[1] += atof(Cmd_Argv(3));
3700 origin[2] += atof(Cmd_Argv(4));
3702 else if (!strcmp(Cmd_Argv(1), "movex"))
3704 if (Cmd_Argc() != 3)
3706 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3709 origin[0] += atof(Cmd_Argv(2));
3711 else if (!strcmp(Cmd_Argv(1), "movey"))
3713 if (Cmd_Argc() != 3)
3715 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3718 origin[1] += atof(Cmd_Argv(2));
3720 else if (!strcmp(Cmd_Argv(1), "movez"))
3722 if (Cmd_Argc() != 3)
3724 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3727 origin[2] += atof(Cmd_Argv(2));
3729 else if (!strcmp(Cmd_Argv(1), "angles"))
3731 if (Cmd_Argc() != 5)
3733 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3736 angles[0] = atof(Cmd_Argv(2));
3737 angles[1] = atof(Cmd_Argv(3));
3738 angles[2] = atof(Cmd_Argv(4));
3740 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3742 if (Cmd_Argc() != 3)
3744 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3747 angles[0] = atof(Cmd_Argv(2));
3749 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3751 if (Cmd_Argc() != 3)
3753 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3756 angles[1] = atof(Cmd_Argv(2));
3758 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3760 if (Cmd_Argc() != 3)
3762 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3765 angles[2] = atof(Cmd_Argv(2));
3767 else if (!strcmp(Cmd_Argv(1), "color"))
3769 if (Cmd_Argc() != 5)
3771 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3774 color[0] = atof(Cmd_Argv(2));
3775 color[1] = atof(Cmd_Argv(3));
3776 color[2] = atof(Cmd_Argv(4));
3778 else if (!strcmp(Cmd_Argv(1), "radius"))
3780 if (Cmd_Argc() != 3)
3782 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3785 radius = atof(Cmd_Argv(2));
3787 else if (!strcmp(Cmd_Argv(1), "style"))
3789 if (Cmd_Argc() != 3)
3791 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3794 style = atoi(Cmd_Argv(2));
3796 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3800 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3803 if (Cmd_Argc() == 3)
3804 strcpy(cubemapname, Cmd_Argv(2));
3808 else if (!strcmp(Cmd_Argv(1), "shadows"))
3810 if (Cmd_Argc() != 3)
3812 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3815 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3817 else if (!strcmp(Cmd_Argv(1), "corona"))
3819 if (Cmd_Argc() != 3)
3821 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3824 corona = atof(Cmd_Argv(2));
3826 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3828 if (Cmd_Argc() != 3)
3830 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3833 coronasizescale = atof(Cmd_Argv(2));
3835 else if (!strcmp(Cmd_Argv(1), "ambient"))
3837 if (Cmd_Argc() != 3)
3839 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3842 ambientscale = atof(Cmd_Argv(2));
3844 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3846 if (Cmd_Argc() != 3)
3848 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3851 diffusescale = atof(Cmd_Argv(2));
3853 else if (!strcmp(Cmd_Argv(1), "specular"))
3855 if (Cmd_Argc() != 3)
3857 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3860 specularscale = atof(Cmd_Argv(2));
3862 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3864 if (Cmd_Argc() != 3)
3866 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3869 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3871 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3873 if (Cmd_Argc() != 3)
3875 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3878 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3882 Con_Print("usage: r_editlights_edit [property] [value]\n");
3883 Con_Print("Selected light's properties:\n");
3884 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3885 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3886 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3887 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3888 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3889 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3890 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3891 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3892 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3893 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3894 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3895 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3896 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3897 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3900 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3901 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3904 void R_Shadow_EditLights_EditAll_f(void)
3908 if (!r_editlights.integer)
3910 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3914 for (light = r_shadow_worldlightchain;light;light = light->next)
3916 R_Shadow_SelectLight(light);
3917 R_Shadow_EditLights_Edit_f();
3921 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3923 int lightnumber, lightcount;
3927 if (!r_editlights.integer)
3933 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3934 if (light == r_shadow_selectedlight)
3935 lightnumber = lightcount;
3936 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;
3937 if (r_shadow_selectedlight == NULL)
3939 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3940 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;
3941 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;
3942 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;
3943 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3944 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3945 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3946 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;
3947 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3948 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3949 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3950 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3951 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3952 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;
3953 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;
3956 void R_Shadow_EditLights_ToggleShadow_f(void)
3958 if (!r_editlights.integer)
3960 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3963 if (!r_shadow_selectedlight)
3965 Con_Print("No selected light.\n");
3968 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);
3971 void R_Shadow_EditLights_ToggleCorona_f(void)
3973 if (!r_editlights.integer)
3975 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3978 if (!r_shadow_selectedlight)
3980 Con_Print("No selected light.\n");
3983 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);
3986 void R_Shadow_EditLights_Remove_f(void)
3988 if (!r_editlights.integer)
3990 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3993 if (!r_shadow_selectedlight)
3995 Con_Print("No selected light.\n");
3998 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3999 r_shadow_selectedlight = NULL;
4002 void R_Shadow_EditLights_Help_f(void)
4005 "Documentation on r_editlights system:\n"
4007 "r_editlights : enable/disable editing mode\n"
4008 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4009 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4010 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4011 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4012 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4013 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
4014 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
4016 "r_editlights_help : this help\n"
4017 "r_editlights_clear : remove all lights\n"
4018 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4019 "r_editlights_save : save to .rtlights file\n"
4020 "r_editlights_spawn : create a light with default settings\n"
4021 "r_editlights_edit command : edit selected light - more documentation below\n"
4022 "r_editlights_remove : remove selected light\n"
4023 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4024 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4025 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4027 "origin x y z : set light location\n"
4028 "originx x: set x component of light location\n"
4029 "originy y: set y component of light location\n"
4030 "originz z: set z component of light location\n"
4031 "move x y z : adjust light location\n"
4032 "movex x: adjust x component of light location\n"
4033 "movey y: adjust y component of light location\n"
4034 "movez z: adjust z component of light location\n"
4035 "angles x y z : set light angles\n"
4036 "anglesx x: set x component of light angles\n"
4037 "anglesy y: set y component of light angles\n"
4038 "anglesz z: set z component of light angles\n"
4039 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4040 "radius radius : set radius (size) of light\n"
4041 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4042 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4043 "shadows 1/0 : turn on/off shadows\n"
4044 "corona n : set corona intensity\n"
4045 "coronasize n : set corona size (0-1)\n"
4046 "ambient n : set ambient intensity (0-1)\n"
4047 "diffuse n : set diffuse intensity (0-1)\n"
4048 "specular n : set specular intensity (0-1)\n"
4049 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4050 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4051 "<nothing> : print light properties to console\n"
4055 void R_Shadow_EditLights_CopyInfo_f(void)
4057 if (!r_editlights.integer)
4059 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4062 if (!r_shadow_selectedlight)
4064 Con_Print("No selected light.\n");
4067 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4068 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4069 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4070 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4071 if (r_shadow_selectedlight->cubemapname)
4072 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
4074 r_shadow_bufferlight.cubemapname[0] = 0;
4075 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4076 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4077 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4078 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4079 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4080 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4081 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4084 void R_Shadow_EditLights_PasteInfo_f(void)
4086 if (!r_editlights.integer)
4088 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4091 if (!r_shadow_selectedlight)
4093 Con_Print("No selected light.\n");
4096 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);
4099 void R_Shadow_EditLights_Init(void)
4101 Cvar_RegisterVariable(&r_editlights);
4102 Cvar_RegisterVariable(&r_editlights_cursordistance);
4103 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4104 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4105 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4106 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4107 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
4108 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
4109 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
4110 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
4111 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
4112 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
4113 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
4114 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
4115 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
4116 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
4117 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
4118 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
4119 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
4120 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
4121 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
4122 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);