3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_STENCIL,
149 R_SHADOW_RENDERMODE_STENCILTWOSIDE,
150 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
151 R_SHADOW_RENDERMODE_LIGHT_DOT3,
152 R_SHADOW_RENDERMODE_LIGHT_GLSL,
153 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
154 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
156 r_shadow_rendermode_t;
158 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
159 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
162 int maxshadowtriangles;
165 int maxshadowvertices;
166 float *shadowvertex3f;
179 int r_shadow_buffer_numleafpvsbytes;
180 unsigned char *r_shadow_buffer_leafpvs;
181 int *r_shadow_buffer_leaflist;
183 int r_shadow_buffer_numsurfacepvsbytes;
184 unsigned char *r_shadow_buffer_surfacepvs;
185 int *r_shadow_buffer_surfacelist;
187 rtexturepool_t *r_shadow_texturepool;
188 rtexture_t *r_shadow_attenuation2dtexture;
189 rtexture_t *r_shadow_attenuation3dtexture;
191 // lights are reloaded when this changes
192 char r_shadow_mapname[MAX_QPATH];
194 // used only for light filters (cubemaps)
195 rtexturepool_t *r_shadow_filters_texturepool;
197 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
198 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
199 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
200 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
201 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
202 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
203 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
204 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
205 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
206 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
207 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
208 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
209 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
210 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal culling optimizations on dynamic lights (slow! you probably don't want this!)"};
211 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
212 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"};
213 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
214 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
215 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
216 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
217 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
218 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
219 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
220 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
221 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
222 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
223 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
224 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
225 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
226 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
227 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
229 float r_shadow_attenpower, r_shadow_attenscale;
231 rtlight_t *r_shadow_compilingrtlight;
232 dlight_t *r_shadow_worldlightchain;
233 dlight_t *r_shadow_selectedlight;
234 dlight_t r_shadow_bufferlight;
235 vec3_t r_editlights_cursorlocation;
237 extern int con_vislines;
239 typedef struct cubemapinfo_s
246 #define MAX_CUBEMAPS 256
247 static int numcubemaps;
248 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
250 void R_Shadow_UncompileWorldLights(void);
251 void R_Shadow_ClearWorldLights(void);
252 void R_Shadow_SaveWorldLights(void);
253 void R_Shadow_LoadWorldLights(void);
254 void R_Shadow_LoadLightsFile(void);
255 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
256 void R_Shadow_EditLights_Reload_f(void);
257 void R_Shadow_ValidateCvars(void);
258 static void R_Shadow_MakeTextures(void);
259 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
261 void r_shadow_start(void)
263 // allocate vertex processing arrays
265 r_shadow_attenuation2dtexture = NULL;
266 r_shadow_attenuation3dtexture = NULL;
267 r_shadow_texturepool = NULL;
268 r_shadow_filters_texturepool = NULL;
269 R_Shadow_ValidateCvars();
270 R_Shadow_MakeTextures();
271 maxshadowtriangles = 0;
272 shadowelements = NULL;
273 maxshadowvertices = 0;
274 shadowvertex3f = NULL;
282 shadowmarklist = NULL;
284 r_shadow_buffer_numleafpvsbytes = 0;
285 r_shadow_buffer_leafpvs = NULL;
286 r_shadow_buffer_leaflist = NULL;
287 r_shadow_buffer_numsurfacepvsbytes = 0;
288 r_shadow_buffer_surfacepvs = NULL;
289 r_shadow_buffer_surfacelist = NULL;
292 void r_shadow_shutdown(void)
294 R_Shadow_UncompileWorldLights();
296 r_shadow_attenuation2dtexture = NULL;
297 r_shadow_attenuation3dtexture = NULL;
298 R_FreeTexturePool(&r_shadow_texturepool);
299 R_FreeTexturePool(&r_shadow_filters_texturepool);
300 maxshadowtriangles = 0;
302 Mem_Free(shadowelements);
303 shadowelements = NULL;
305 Mem_Free(shadowvertex3f);
306 shadowvertex3f = NULL;
309 Mem_Free(vertexupdate);
312 Mem_Free(vertexremap);
318 Mem_Free(shadowmark);
321 Mem_Free(shadowmarklist);
322 shadowmarklist = NULL;
324 r_shadow_buffer_numleafpvsbytes = 0;
325 if (r_shadow_buffer_leafpvs)
326 Mem_Free(r_shadow_buffer_leafpvs);
327 r_shadow_buffer_leafpvs = NULL;
328 if (r_shadow_buffer_leaflist)
329 Mem_Free(r_shadow_buffer_leaflist);
330 r_shadow_buffer_leaflist = NULL;
331 r_shadow_buffer_numsurfacepvsbytes = 0;
332 if (r_shadow_buffer_surfacepvs)
333 Mem_Free(r_shadow_buffer_surfacepvs);
334 r_shadow_buffer_surfacepvs = NULL;
335 if (r_shadow_buffer_surfacelist)
336 Mem_Free(r_shadow_buffer_surfacelist);
337 r_shadow_buffer_surfacelist = NULL;
340 void r_shadow_newmap(void)
344 void R_Shadow_Help_f(void)
347 "Documentation on r_shadow system:\n"
349 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
350 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
351 "r_shadow_debuglight : render only this light number (-1 = all)\n"
352 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
353 "r_shadow_gloss2intensity : brightness of forced gloss\n"
354 "r_shadow_glossintensity : brightness of textured gloss\n"
355 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
356 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
357 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
358 "r_shadow_portallight : use portal visibility for static light precomputation\n"
359 "r_shadow_projectdistance : shadow volume projection distance\n"
360 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
361 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
362 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
363 "r_shadow_realtime_world : use high quality world lighting mode\n"
364 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
365 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
366 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
367 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
368 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
369 "r_shadow_scissor : use scissor optimization\n"
370 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
371 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
372 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
373 "r_showlighting : useful for performance testing; bright = slow!\n"
374 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
376 "r_shadow_help : this help\n"
380 void R_Shadow_Init(void)
382 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
383 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
384 Cvar_RegisterVariable(&r_shadow_debuglight);
385 Cvar_RegisterVariable(&r_shadow_gloss);
386 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
387 Cvar_RegisterVariable(&r_shadow_glossintensity);
388 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
389 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
390 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
391 Cvar_RegisterVariable(&r_shadow_portallight);
392 Cvar_RegisterVariable(&r_shadow_projectdistance);
393 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
394 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
395 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
396 Cvar_RegisterVariable(&r_shadow_realtime_world);
397 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
398 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
399 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
400 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
401 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
402 Cvar_RegisterVariable(&r_shadow_scissor);
403 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
404 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
405 Cvar_RegisterVariable(&r_shadow_texture3d);
406 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
407 if (gamemode == GAME_TENEBRAE)
409 Cvar_SetValue("r_shadow_gloss", 2);
410 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
412 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
413 R_Shadow_EditLights_Init();
414 r_shadow_worldlightchain = NULL;
415 maxshadowtriangles = 0;
416 shadowelements = NULL;
417 maxshadowvertices = 0;
418 shadowvertex3f = NULL;
426 shadowmarklist = NULL;
428 r_shadow_buffer_numleafpvsbytes = 0;
429 r_shadow_buffer_leafpvs = NULL;
430 r_shadow_buffer_leaflist = NULL;
431 r_shadow_buffer_numsurfacepvsbytes = 0;
432 r_shadow_buffer_surfacepvs = NULL;
433 r_shadow_buffer_surfacelist = NULL;
434 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
437 matrix4x4_t matrix_attenuationxyz =
440 {0.5, 0.0, 0.0, 0.5},
441 {0.0, 0.5, 0.0, 0.5},
442 {0.0, 0.0, 0.5, 0.5},
447 matrix4x4_t matrix_attenuationz =
450 {0.0, 0.0, 0.5, 0.5},
451 {0.0, 0.0, 0.0, 0.5},
452 {0.0, 0.0, 0.0, 0.5},
457 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
459 // make sure shadowelements is big enough for this volume
460 if (maxshadowtriangles < numtriangles)
462 maxshadowtriangles = numtriangles;
464 Mem_Free(shadowelements);
465 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
467 // make sure shadowvertex3f is big enough for this volume
468 if (maxshadowvertices < numvertices)
470 maxshadowvertices = numvertices;
472 Mem_Free(shadowvertex3f);
473 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
477 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
479 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
480 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
481 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
483 if (r_shadow_buffer_leafpvs)
484 Mem_Free(r_shadow_buffer_leafpvs);
485 if (r_shadow_buffer_leaflist)
486 Mem_Free(r_shadow_buffer_leaflist);
487 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
488 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
489 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
491 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
493 if (r_shadow_buffer_surfacepvs)
494 Mem_Free(r_shadow_buffer_surfacepvs);
495 if (r_shadow_buffer_surfacelist)
496 Mem_Free(r_shadow_buffer_surfacelist);
497 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
498 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
499 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
503 void R_Shadow_PrepareShadowMark(int numtris)
505 // make sure shadowmark is big enough for this volume
506 if (maxshadowmark < numtris)
508 maxshadowmark = numtris;
510 Mem_Free(shadowmark);
512 Mem_Free(shadowmarklist);
513 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
514 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
518 // if shadowmarkcount wrapped we clear the array and adjust accordingly
519 if (shadowmarkcount == 0)
522 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
527 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, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
530 int outtriangles = 0, outvertices = 0;
533 float ratio, direction[3], projectvector[3];
535 if (projectdirection)
536 VectorScale(projectdirection, projectdistance, projectvector);
538 VectorClear(projectvector);
540 if (maxvertexupdate < innumvertices)
542 maxvertexupdate = innumvertices;
544 Mem_Free(vertexupdate);
546 Mem_Free(vertexremap);
547 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
548 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
552 if (vertexupdatenum == 0)
555 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
556 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
559 for (i = 0;i < numshadowmarktris;i++)
560 shadowmark[shadowmarktris[i]] = shadowmarkcount;
562 // create the vertices
563 if (projectdirection)
565 for (i = 0;i < numshadowmarktris;i++)
567 element = inelement3i + shadowmarktris[i] * 3;
568 for (j = 0;j < 3;j++)
570 if (vertexupdate[element[j]] != vertexupdatenum)
572 vertexupdate[element[j]] = vertexupdatenum;
573 vertexremap[element[j]] = outvertices;
574 vertex = invertex3f + element[j] * 3;
575 // project one copy of the vertex according to projectvector
576 VectorCopy(vertex, outvertex3f);
577 VectorAdd(vertex, projectvector, (outvertex3f + 3));
586 for (i = 0;i < numshadowmarktris;i++)
588 element = inelement3i + shadowmarktris[i] * 3;
589 for (j = 0;j < 3;j++)
591 if (vertexupdate[element[j]] != vertexupdatenum)
593 vertexupdate[element[j]] = vertexupdatenum;
594 vertexremap[element[j]] = outvertices;
595 vertex = invertex3f + element[j] * 3;
596 // project one copy of the vertex to the sphere radius of the light
597 // (FIXME: would projecting it to the light box be better?)
598 VectorSubtract(vertex, projectorigin, direction);
599 ratio = projectdistance / VectorLength(direction);
600 VectorCopy(vertex, outvertex3f);
601 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
609 for (i = 0;i < numshadowmarktris;i++)
611 int remappedelement[3];
613 const int *neighbortriangle;
615 markindex = shadowmarktris[i] * 3;
616 element = inelement3i + markindex;
617 neighbortriangle = inneighbor3i + markindex;
618 // output the front and back triangles
619 outelement3i[0] = vertexremap[element[0]];
620 outelement3i[1] = vertexremap[element[1]];
621 outelement3i[2] = vertexremap[element[2]];
622 outelement3i[3] = vertexremap[element[2]] + 1;
623 outelement3i[4] = vertexremap[element[1]] + 1;
624 outelement3i[5] = vertexremap[element[0]] + 1;
628 // output the sides (facing outward from this triangle)
629 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
631 remappedelement[0] = vertexremap[element[0]];
632 remappedelement[1] = vertexremap[element[1]];
633 outelement3i[0] = remappedelement[1];
634 outelement3i[1] = remappedelement[0];
635 outelement3i[2] = remappedelement[0] + 1;
636 outelement3i[3] = remappedelement[1];
637 outelement3i[4] = remappedelement[0] + 1;
638 outelement3i[5] = remappedelement[1] + 1;
643 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
645 remappedelement[1] = vertexremap[element[1]];
646 remappedelement[2] = vertexremap[element[2]];
647 outelement3i[0] = remappedelement[2];
648 outelement3i[1] = remappedelement[1];
649 outelement3i[2] = remappedelement[1] + 1;
650 outelement3i[3] = remappedelement[2];
651 outelement3i[4] = remappedelement[1] + 1;
652 outelement3i[5] = remappedelement[2] + 1;
657 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
659 remappedelement[0] = vertexremap[element[0]];
660 remappedelement[2] = vertexremap[element[2]];
661 outelement3i[0] = remappedelement[0];
662 outelement3i[1] = remappedelement[2];
663 outelement3i[2] = remappedelement[2] + 1;
664 outelement3i[3] = remappedelement[0];
665 outelement3i[4] = remappedelement[2] + 1;
666 outelement3i[5] = remappedelement[0] + 1;
673 *outnumvertices = outvertices;
677 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris)
680 if (projectdistance < 0.1)
682 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
685 if (!numverts || !nummarktris)
687 // make sure shadowelements is big enough for this volume
688 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
689 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
690 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
691 r_refdef.stats.lights_dynamicshadowtriangles += tris;
692 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
695 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
701 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
703 tend = firsttriangle + numtris;
704 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
705 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
706 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
708 // surface box entirely inside light box, no box cull
709 if (projectdirection)
711 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
713 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
714 if (DotProduct(normal, projectdirection) < 0)
715 shadowmarklist[numshadowmark++] = t;
720 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
721 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
722 shadowmarklist[numshadowmark++] = t;
727 // surface box not entirely inside light box, cull each triangle
728 if (projectdirection)
730 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
732 v[0] = invertex3f + e[0] * 3;
733 v[1] = invertex3f + e[1] * 3;
734 v[2] = invertex3f + e[2] * 3;
735 TriangleNormal(v[0], v[1], v[2], normal);
736 if (DotProduct(normal, projectdirection) < 0
737 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
738 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
739 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
740 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
741 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
742 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
743 shadowmarklist[numshadowmark++] = t;
748 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
750 v[0] = invertex3f + e[0] * 3;
751 v[1] = invertex3f + e[1] * 3;
752 v[2] = invertex3f + e[2] * 3;
753 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
754 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
755 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
756 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
757 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
758 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
759 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
760 shadowmarklist[numshadowmark++] = t;
766 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
768 if (r_shadow_compilingrtlight)
770 // if we're compiling an rtlight, capture the mesh
771 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
774 r_refdef.stats.lights_shadowtriangles += numtriangles;
776 R_Mesh_VertexPointer(vertex3f);
777 GL_LockArrays(0, numvertices);
778 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
780 // decrement stencil if backface is behind depthbuffer
781 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
782 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
783 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
784 // increment stencil if frontface is behind depthbuffer
785 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
786 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
788 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
793 static void R_Shadow_MakeTextures(void)
796 float v[3], intensity;
798 R_FreeTexturePool(&r_shadow_texturepool);
799 r_shadow_texturepool = R_AllocTexturePool();
800 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
801 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
802 #define ATTEN2DSIZE 64
803 #define ATTEN3DSIZE 32
804 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
805 for (y = 0;y < ATTEN2DSIZE;y++)
807 for (x = 0;x < ATTEN2DSIZE;x++)
809 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
810 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
812 intensity = 1.0f - sqrt(DotProduct(v, v));
814 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
815 d = (int)bound(0, intensity, 255);
816 data[(y*ATTEN2DSIZE+x)*4+0] = d;
817 data[(y*ATTEN2DSIZE+x)*4+1] = d;
818 data[(y*ATTEN2DSIZE+x)*4+2] = d;
819 data[(y*ATTEN2DSIZE+x)*4+3] = d;
822 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
823 if (r_shadow_texture3d.integer && gl_texture3d)
825 for (z = 0;z < ATTEN3DSIZE;z++)
827 for (y = 0;y < ATTEN3DSIZE;y++)
829 for (x = 0;x < ATTEN3DSIZE;x++)
831 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
832 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
833 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
834 intensity = 1.0f - sqrt(DotProduct(v, v));
836 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
837 d = (int)bound(0, intensity, 255);
838 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
839 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
840 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
841 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
845 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
850 void R_Shadow_ValidateCvars(void)
852 if (r_shadow_texture3d.integer && !gl_texture3d)
853 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
854 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
855 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
858 // light currently being rendered
859 rtlight_t *r_shadow_rtlight;
861 // this is the location of the light in entity space
862 vec3_t r_shadow_entitylightorigin;
863 // this transforms entity coordinates to light filter cubemap coordinates
864 // (also often used for other purposes)
865 matrix4x4_t r_shadow_entitytolight;
866 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
867 // of attenuation texturing in full 3D (Z result often ignored)
868 matrix4x4_t r_shadow_entitytoattenuationxyz;
869 // this transforms only the Z to S, and T is always 0.5
870 matrix4x4_t r_shadow_entitytoattenuationz;
872 void R_Shadow_RenderMode_Begin(void)
874 R_Shadow_ValidateCvars();
876 if (!r_shadow_attenuation2dtexture
877 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
878 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
879 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
880 R_Shadow_MakeTextures();
883 R_Mesh_ColorPointer(NULL);
884 R_Mesh_ResetTextureState();
885 GL_BlendFunc(GL_ONE, GL_ZERO);
887 GL_Color(0, 0, 0, 1);
888 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
890 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
892 if (gl_ext_stenciltwoside.integer)
893 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
895 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
897 if (r_glsl.integer && gl_support_fragment_shader)
898 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
899 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
900 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
902 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
905 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
907 r_shadow_rtlight = rtlight;
910 void R_Shadow_RenderMode_Reset(void)
913 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
915 qglUseProgramObjectARB(0);CHECKGLERROR
917 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
919 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
921 R_Mesh_ColorPointer(NULL);
922 R_Mesh_ResetTextureState();
925 void R_Shadow_RenderMode_StencilShadowVolumes(void)
928 R_Shadow_RenderMode_Reset();
929 GL_Color(1, 1, 1, 1);
930 GL_ColorMask(0, 0, 0, 0);
931 GL_BlendFunc(GL_ONE, GL_ZERO);
933 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
934 qglDepthFunc(GL_LESS);CHECKGLERROR
935 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
936 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
937 r_shadow_rendermode = r_shadow_shadowingrendermode;
938 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
940 GL_CullFace(GL_NONE);
941 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
942 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
943 qglStencilMask(~0);CHECKGLERROR
944 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
945 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
946 qglStencilMask(~0);CHECKGLERROR
947 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
951 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
952 qglStencilMask(~0);CHECKGLERROR
953 // this is changed by every shadow render so its value here is unimportant
954 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
956 GL_Clear(GL_STENCIL_BUFFER_BIT);
957 r_refdef.stats.lights_clears++;
960 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
963 R_Shadow_RenderMode_Reset();
964 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
966 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
967 //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
968 GL_Color(1, 1, 1, 1);
969 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
972 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
976 qglDepthFunc(GL_EQUAL);CHECKGLERROR
980 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
984 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
986 qglStencilMask(~0);CHECKGLERROR
987 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
988 // only draw light where this geometry was already rendered AND the
989 // stencil is 128 (values other than this mean shadow)
990 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
991 r_shadow_rendermode = r_shadow_lightingrendermode;
992 // do global setup needed for the chosen lighting mode
993 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
995 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
996 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
997 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
998 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
999 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1000 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1001 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1002 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1003 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1004 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1005 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1006 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1007 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1012 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1015 R_Shadow_RenderMode_Reset();
1016 GL_BlendFunc(GL_ONE, GL_ONE);
1017 GL_DepthMask(false);
1018 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1019 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1020 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1021 if (r_showshadowvolumes.integer >= 2)
1023 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
1027 qglDepthFunc(GL_GEQUAL);CHECKGLERROR
1029 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1030 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1033 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1036 R_Shadow_RenderMode_Reset();
1037 GL_BlendFunc(GL_ONE, GL_ONE);
1038 GL_DepthMask(false);
1039 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1040 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1041 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1042 if (r_showshadowvolumes.integer >= 2)
1044 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
1046 else if (transparent)
1048 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1052 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1056 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1060 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1062 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1065 void R_Shadow_RenderMode_End(void)
1068 R_Shadow_RenderMode_Reset();
1069 R_Shadow_RenderMode_ActiveLight(NULL);
1070 GL_BlendFunc(GL_ONE, GL_ZERO);
1072 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1073 //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
1074 GL_Color(1, 1, 1, 1);
1075 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1076 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1077 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1078 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1079 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1080 if (gl_support_stenciltwoside)
1082 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1084 qglStencilMask(~0);CHECKGLERROR
1085 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1086 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1089 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1091 int i, ix1, iy1, ix2, iy2;
1092 float x1, y1, x2, y2;
1095 mplane_t planes[11];
1096 float vertex3f[256*3];
1098 // if view is inside the light box, just say yes it's visible
1099 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1101 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1105 // create a temporary brush describing the area the light can affect in worldspace
1106 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1107 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1108 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1109 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1110 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1111 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1112 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1113 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1114 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1115 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1116 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1118 // turn the brush into a mesh
1119 memset(&mesh, 0, sizeof(rmesh_t));
1120 mesh.maxvertices = 256;
1121 mesh.vertex3f = vertex3f;
1122 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1123 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1125 // if that mesh is empty, the light is not visible at all
1126 if (!mesh.numvertices)
1129 if (!r_shadow_scissor.integer)
1132 // if that mesh is not empty, check what area of the screen it covers
1133 x1 = y1 = x2 = y2 = 0;
1135 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1136 for (i = 0;i < mesh.numvertices;i++)
1138 VectorCopy(mesh.vertex3f + i * 3, v);
1139 GL_TransformToScreen(v, v2);
1140 //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]);
1143 if (x1 > v2[0]) x1 = v2[0];
1144 if (x2 < v2[0]) x2 = v2[0];
1145 if (y1 > v2[1]) y1 = v2[1];
1146 if (y2 < v2[1]) y2 = v2[1];
1155 // now convert the scissor rectangle to integer screen coordinates
1156 ix1 = (int)(x1 - 1.0f);
1157 iy1 = (int)(y1 - 1.0f);
1158 ix2 = (int)(x2 + 1.0f);
1159 iy2 = (int)(y2 + 1.0f);
1160 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1162 // clamp it to the screen
1163 if (ix1 < r_view.x) ix1 = r_view.x;
1164 if (iy1 < r_view.y) iy1 = r_view.y;
1165 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1166 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1168 // if it is inside out, it's not visible
1169 if (ix2 <= ix1 || iy2 <= iy1)
1172 // the light area is visible, set up the scissor rectangle
1173 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1174 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1175 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1176 r_refdef.stats.lights_scissored++;
1180 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1182 int numverts = surface->num_vertices;
1183 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1184 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1185 float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1186 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1187 if (r_textureunits.integer >= 3)
1189 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1191 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1192 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1193 if ((dot = DotProduct(n, v)) < 0)
1195 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1196 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1197 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1198 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1199 if (r_refdef.fogenabled)
1201 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1202 VectorScale(color4f, f, color4f);
1206 VectorClear(color4f);
1210 else if (r_textureunits.integer >= 2)
1212 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1214 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1215 if ((dist = fabs(v[2])) < 1)
1217 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1218 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1219 if ((dot = DotProduct(n, v)) < 0)
1221 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1222 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1223 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1224 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1228 color4f[0] = ambientcolor[0] * distintensity;
1229 color4f[1] = ambientcolor[1] * distintensity;
1230 color4f[2] = ambientcolor[2] * distintensity;
1232 if (r_refdef.fogenabled)
1234 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1235 VectorScale(color4f, f, color4f);
1239 VectorClear(color4f);
1245 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1247 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1248 if ((dist = DotProduct(v, v)) < 1)
1251 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1252 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1253 if ((dot = DotProduct(n, v)) < 0)
1255 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1256 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1257 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1258 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1262 color4f[0] = ambientcolor[0] * distintensity;
1263 color4f[1] = ambientcolor[1] * distintensity;
1264 color4f[2] = ambientcolor[2] * distintensity;
1266 if (r_refdef.fogenabled)
1268 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1269 VectorScale(color4f, f, color4f);
1273 VectorClear(color4f);
1279 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1281 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1283 int surfacelistindex;
1284 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1286 const msurface_t *surface = surfacelist[surfacelistindex];
1288 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1289 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1290 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1291 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1292 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1294 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1296 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1297 // the cubemap normalizes this for us
1298 out3f[0] = DotProduct(svector3f, lightdir);
1299 out3f[1] = DotProduct(tvector3f, lightdir);
1300 out3f[2] = DotProduct(normal3f, lightdir);
1305 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1307 int surfacelistindex;
1308 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1310 const msurface_t *surface = surfacelist[surfacelistindex];
1312 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1313 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1314 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1315 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1316 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1317 float lightdir[3], eyedir[3], halfdir[3];
1318 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1320 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1321 VectorNormalize(lightdir);
1322 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1323 VectorNormalize(eyedir);
1324 VectorAdd(lightdir, eyedir, halfdir);
1325 // the cubemap normalizes this for us
1326 out3f[0] = DotProduct(svector3f, halfdir);
1327 out3f[1] = DotProduct(tvector3f, halfdir);
1328 out3f[2] = DotProduct(normal3f, halfdir);
1333 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1335 // used to display how many times a surface is lit for level design purposes
1336 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1337 R_Mesh_ColorPointer(NULL);
1338 R_Mesh_ResetTextureState();
1339 RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1340 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1341 GL_LockArrays(0, 0);
1344 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1346 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1347 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1348 R_SetupSurfaceShader(lightcolorbase, false);
1349 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1350 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1351 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1352 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1353 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1355 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1357 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1358 GL_LockArrays(0, 0);
1359 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1361 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1365 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1367 // shared final code for all the dot3 layers
1369 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1370 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1372 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1373 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1374 GL_LockArrays(0, 0);
1378 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1381 // colorscale accounts for how much we multiply the brightness
1384 // mult is how many times the final pass of the lighting will be
1385 // performed to get more brightness than otherwise possible.
1387 // Limit mult to 64 for sanity sake.
1389 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1391 // 3 3D combine path (Geforce3, Radeon 8500)
1392 memset(&m, 0, sizeof(m));
1393 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1394 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1395 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1396 m.tex[1] = R_GetTexture(basetexture);
1397 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1398 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1399 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1400 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1401 m.texmatrix[2] = r_shadow_entitytolight;
1402 GL_BlendFunc(GL_ONE, GL_ONE);
1404 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1406 // 2 3D combine path (Geforce3, original Radeon)
1407 memset(&m, 0, sizeof(m));
1408 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1409 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1410 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1411 m.tex[1] = R_GetTexture(basetexture);
1412 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1413 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1414 GL_BlendFunc(GL_ONE, GL_ONE);
1416 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1418 // 4 2D combine path (Geforce3, Radeon 8500)
1419 memset(&m, 0, sizeof(m));
1420 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1421 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1422 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1423 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1424 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1425 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1426 m.tex[2] = R_GetTexture(basetexture);
1427 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1428 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1429 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1431 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1432 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1433 m.texmatrix[3] = r_shadow_entitytolight;
1435 GL_BlendFunc(GL_ONE, GL_ONE);
1437 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1439 // 3 2D combine path (Geforce3, original Radeon)
1440 memset(&m, 0, sizeof(m));
1441 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1442 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1443 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1444 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1445 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1446 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1447 m.tex[2] = R_GetTexture(basetexture);
1448 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1449 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1450 GL_BlendFunc(GL_ONE, GL_ONE);
1454 // 2/2/2 2D combine path (any dot3 card)
1455 memset(&m, 0, sizeof(m));
1456 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1457 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1458 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1459 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1460 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1461 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1462 R_Mesh_TextureState(&m);
1463 GL_ColorMask(0,0,0,1);
1464 GL_BlendFunc(GL_ONE, GL_ZERO);
1465 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1466 GL_LockArrays(0, 0);
1469 memset(&m, 0, sizeof(m));
1470 m.tex[0] = R_GetTexture(basetexture);
1471 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1472 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1473 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1475 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1476 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1477 m.texmatrix[1] = r_shadow_entitytolight;
1479 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1481 // this final code is shared
1482 R_Mesh_TextureState(&m);
1483 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1486 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1489 // colorscale accounts for how much we multiply the brightness
1492 // mult is how many times the final pass of the lighting will be
1493 // performed to get more brightness than otherwise possible.
1495 // Limit mult to 64 for sanity sake.
1497 // generate normalization cubemap texcoords
1498 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1499 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1501 // 3/2 3D combine path (Geforce3, Radeon 8500)
1502 memset(&m, 0, sizeof(m));
1503 m.tex[0] = R_GetTexture(normalmaptexture);
1504 m.texcombinergb[0] = GL_REPLACE;
1505 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1506 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1507 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1508 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1509 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1510 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1511 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1512 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1513 R_Mesh_TextureState(&m);
1514 GL_ColorMask(0,0,0,1);
1515 GL_BlendFunc(GL_ONE, GL_ZERO);
1516 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1517 GL_LockArrays(0, 0);
1520 memset(&m, 0, sizeof(m));
1521 m.tex[0] = R_GetTexture(basetexture);
1522 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1523 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1524 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1526 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1527 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1528 m.texmatrix[1] = r_shadow_entitytolight;
1530 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1532 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1534 // 1/2/2 3D combine path (original Radeon)
1535 memset(&m, 0, sizeof(m));
1536 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1537 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1538 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1539 R_Mesh_TextureState(&m);
1540 GL_ColorMask(0,0,0,1);
1541 GL_BlendFunc(GL_ONE, GL_ZERO);
1542 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1543 GL_LockArrays(0, 0);
1546 memset(&m, 0, sizeof(m));
1547 m.tex[0] = R_GetTexture(normalmaptexture);
1548 m.texcombinergb[0] = GL_REPLACE;
1549 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1550 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1551 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1552 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1553 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1554 R_Mesh_TextureState(&m);
1555 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1556 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1557 GL_LockArrays(0, 0);
1560 memset(&m, 0, sizeof(m));
1561 m.tex[0] = R_GetTexture(basetexture);
1562 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1563 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1564 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1566 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1567 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1568 m.texmatrix[1] = r_shadow_entitytolight;
1570 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1572 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1574 // 2/2 3D combine path (original Radeon)
1575 memset(&m, 0, sizeof(m));
1576 m.tex[0] = R_GetTexture(normalmaptexture);
1577 m.texcombinergb[0] = GL_REPLACE;
1578 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1579 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1580 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1581 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1582 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1583 R_Mesh_TextureState(&m);
1584 GL_ColorMask(0,0,0,1);
1585 GL_BlendFunc(GL_ONE, GL_ZERO);
1586 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1587 GL_LockArrays(0, 0);
1590 memset(&m, 0, sizeof(m));
1591 m.tex[0] = R_GetTexture(basetexture);
1592 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1593 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1594 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1595 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1596 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1597 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1599 else if (r_textureunits.integer >= 4)
1601 // 4/2 2D combine path (Geforce3, Radeon 8500)
1602 memset(&m, 0, sizeof(m));
1603 m.tex[0] = R_GetTexture(normalmaptexture);
1604 m.texcombinergb[0] = GL_REPLACE;
1605 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1606 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1607 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1608 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1609 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1610 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1611 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1612 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1613 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1614 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1615 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1616 R_Mesh_TextureState(&m);
1617 GL_ColorMask(0,0,0,1);
1618 GL_BlendFunc(GL_ONE, GL_ZERO);
1619 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1620 GL_LockArrays(0, 0);
1623 memset(&m, 0, sizeof(m));
1624 m.tex[0] = R_GetTexture(basetexture);
1625 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1626 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1627 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1629 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1630 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1631 m.texmatrix[1] = r_shadow_entitytolight;
1633 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1637 // 2/2/2 2D combine path (any dot3 card)
1638 memset(&m, 0, sizeof(m));
1639 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1640 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1641 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1642 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1643 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1644 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1645 R_Mesh_TextureState(&m);
1646 GL_ColorMask(0,0,0,1);
1647 GL_BlendFunc(GL_ONE, GL_ZERO);
1648 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1649 GL_LockArrays(0, 0);
1652 memset(&m, 0, sizeof(m));
1653 m.tex[0] = R_GetTexture(normalmaptexture);
1654 m.texcombinergb[0] = GL_REPLACE;
1655 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1656 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1657 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1658 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1659 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1660 R_Mesh_TextureState(&m);
1661 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1662 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1663 GL_LockArrays(0, 0);
1666 memset(&m, 0, sizeof(m));
1667 m.tex[0] = R_GetTexture(basetexture);
1668 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1669 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1670 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1672 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1673 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1674 m.texmatrix[1] = r_shadow_entitytolight;
1676 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1678 // this final code is shared
1679 R_Mesh_TextureState(&m);
1680 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1683 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1686 // FIXME: detect blendsquare!
1687 //if (!gl_support_blendsquare)
1690 // generate normalization cubemap texcoords
1691 R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1692 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1694 // 2/0/0/1/2 3D combine blendsquare path
1695 memset(&m, 0, sizeof(m));
1696 m.tex[0] = R_GetTexture(normalmaptexture);
1697 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1698 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1699 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1700 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1701 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1702 R_Mesh_TextureState(&m);
1703 GL_ColorMask(0,0,0,1);
1704 // this squares the result
1705 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1706 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1707 GL_LockArrays(0, 0);
1709 // second and third pass
1710 R_Mesh_ResetTextureState();
1711 // square alpha in framebuffer a few times to make it shiny
1712 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1713 // these comments are a test run through this math for intensity 0.5
1714 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1715 // 0.25 * 0.25 = 0.0625 (this is another pass)
1716 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1717 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1718 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1719 GL_LockArrays(0, 0);
1722 memset(&m, 0, sizeof(m));
1723 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1724 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1725 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1726 R_Mesh_TextureState(&m);
1727 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1728 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1729 GL_LockArrays(0, 0);
1732 memset(&m, 0, sizeof(m));
1733 m.tex[0] = R_GetTexture(glosstexture);
1734 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1735 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1736 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1738 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1739 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1740 m.texmatrix[1] = r_shadow_entitytolight;
1742 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1744 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1746 // 2/0/0/2 3D combine blendsquare path
1747 memset(&m, 0, sizeof(m));
1748 m.tex[0] = R_GetTexture(normalmaptexture);
1749 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1750 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1751 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1752 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1753 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1754 R_Mesh_TextureState(&m);
1755 GL_ColorMask(0,0,0,1);
1756 // this squares the result
1757 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1758 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1759 GL_LockArrays(0, 0);
1761 // second and third pass
1762 R_Mesh_ResetTextureState();
1763 // square alpha in framebuffer a few times to make it shiny
1764 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1765 // these comments are a test run through this math for intensity 0.5
1766 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1767 // 0.25 * 0.25 = 0.0625 (this is another pass)
1768 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1769 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1770 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1771 GL_LockArrays(0, 0);
1774 memset(&m, 0, sizeof(m));
1775 m.tex[0] = R_GetTexture(glosstexture);
1776 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1777 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1778 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1779 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1780 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1781 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1785 // 2/0/0/2/2 2D combine blendsquare path
1786 memset(&m, 0, sizeof(m));
1787 m.tex[0] = R_GetTexture(normalmaptexture);
1788 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1789 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1790 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1791 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1792 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1793 R_Mesh_TextureState(&m);
1794 GL_ColorMask(0,0,0,1);
1795 // this squares the result
1796 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1797 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1798 GL_LockArrays(0, 0);
1800 // second and third pass
1801 R_Mesh_ResetTextureState();
1802 // square alpha in framebuffer a few times to make it shiny
1803 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1804 // these comments are a test run through this math for intensity 0.5
1805 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1806 // 0.25 * 0.25 = 0.0625 (this is another pass)
1807 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1808 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1809 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1810 GL_LockArrays(0, 0);
1813 memset(&m, 0, sizeof(m));
1814 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1815 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1816 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1817 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1818 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1819 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1820 R_Mesh_TextureState(&m);
1821 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1822 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1823 GL_LockArrays(0, 0);
1826 memset(&m, 0, sizeof(m));
1827 m.tex[0] = R_GetTexture(glosstexture);
1828 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1829 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1830 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1832 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1833 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1834 m.texmatrix[1] = r_shadow_entitytolight;
1836 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1838 // this final code is shared
1839 R_Mesh_TextureState(&m);
1840 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1843 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1845 // ARB path (any Geforce, any Radeon)
1846 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1847 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1848 qboolean dospecular = specularscale > 0;
1849 if (!doambient && !dodiffuse && !dospecular)
1851 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1852 R_Mesh_ColorPointer(NULL);
1854 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1856 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1860 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1862 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1867 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1869 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1872 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1875 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1877 int surfacelistindex;
1879 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1881 const msurface_t *surface = surfacelist[surfacelistindex];
1882 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1884 for (renders = 0;renders < 64;renders++)
1890 int newnumtriangles;
1892 int newelements[3072];
1896 newnumtriangles = 0;
1898 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1900 const msurface_t *surface = surfacelist[surfacelistindex];
1901 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1903 // due to low fillrate on the cards this vertex lighting path is
1904 // designed for, we manually cull all triangles that do not
1905 // contain a lit vertex
1906 // this builds batches of triangles from multiple surfaces and
1907 // renders them at once
1908 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1910 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1912 if (newnumtriangles)
1914 firstvertex = min(firstvertex, e[0]);
1915 lastvertex = max(lastvertex, e[0]);
1922 firstvertex = min(firstvertex, e[1]);
1923 lastvertex = max(lastvertex, e[1]);
1924 firstvertex = min(firstvertex, e[2]);
1925 lastvertex = max(lastvertex, e[2]);
1931 if (newnumtriangles >= 1024)
1933 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1934 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1935 newnumtriangles = 0;
1942 if (newnumtriangles >= 1)
1944 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1945 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1948 GL_LockArrays(0, 0);
1949 // if we couldn't find any lit triangles, exit early
1952 // now reduce the intensity for the next overbright pass
1953 // we have to clamp to 0 here incase the drivers have improper
1954 // handling of negative colors
1955 // (some old drivers even have improper handling of >1 color)
1957 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1961 const msurface_t *surface = surfacelist[surfacelistindex];
1962 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1964 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1966 c[0] = max(0, c[0] - 1);
1967 c[1] = max(0, c[1] - 1);
1968 c[2] = max(0, c[2] - 1);
1981 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1983 // OpenGL 1.1 path (anything)
1984 model_t *model = rsurface_entity->model;
1985 float ambientcolorbase[3], diffusecolorbase[3];
1986 float ambientcolorpants[3], diffusecolorpants[3];
1987 float ambientcolorshirt[3], diffusecolorshirt[3];
1989 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
1990 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
1991 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
1992 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
1993 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
1994 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
1995 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1996 R_Mesh_ColorPointer(rsurface_array_color4f);
1997 memset(&m, 0, sizeof(m));
1998 m.tex[0] = R_GetTexture(basetexture);
1999 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2000 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2001 if (r_textureunits.integer >= 2)
2004 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2005 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2006 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2007 if (r_textureunits.integer >= 3)
2009 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2010 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2011 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2012 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2015 R_Mesh_TextureState(&m);
2016 RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
2017 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2018 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
2021 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2022 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
2026 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2027 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
2031 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
2033 // FIXME: support MATERIALFLAG_NODEPTHTEST
2034 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2035 // calculate colors to render this texture with
2036 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2037 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2038 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2039 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2041 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2042 GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2043 if (rsurface_texture->colormapping)
2045 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2046 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2049 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2050 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2051 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2054 VectorClear(lightcolorpants);
2057 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2058 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2059 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2062 VectorClear(lightcolorshirt);
2063 switch (r_shadow_rendermode)
2065 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2066 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2067 R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2069 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2070 R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2072 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2073 R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2075 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2076 R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2079 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2085 switch (r_shadow_rendermode)
2087 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2088 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2089 R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2091 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2092 R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2094 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2095 R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2097 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2098 R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2101 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2107 void R_RTLight_Update(dlight_t *light, int isstatic)
2110 rtlight_t *rtlight = &light->rtlight;
2111 R_RTLight_Uncompile(rtlight);
2112 memset(rtlight, 0, sizeof(*rtlight));
2114 VectorCopy(light->origin, rtlight->shadoworigin);
2115 VectorCopy(light->color, rtlight->color);
2116 rtlight->radius = light->radius;
2117 //rtlight->cullradius = rtlight->radius;
2118 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2119 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2120 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2121 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2122 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2123 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2124 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2125 rtlight->cubemapname[0] = 0;
2126 if (light->cubemapname[0])
2127 strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
2128 else if (light->cubemapnum > 0)
2129 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2130 rtlight->shadow = light->shadow;
2131 rtlight->corona = light->corona;
2132 rtlight->style = light->style;
2133 rtlight->isstatic = isstatic;
2134 rtlight->coronasizescale = light->coronasizescale;
2135 rtlight->ambientscale = light->ambientscale;
2136 rtlight->diffusescale = light->diffusescale;
2137 rtlight->specularscale = light->specularscale;
2138 rtlight->flags = light->flags;
2139 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2140 // this has to scale both rotate and translate because this is an already
2141 // inverted matrix (it transforms from world to light space, not the other
2143 scale = 1.0 / rtlight->radius;
2144 Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
2147 // compiles rtlight geometry
2148 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2149 void R_RTLight_Compile(rtlight_t *rtlight)
2151 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2152 entity_render_t *ent = r_refdef.worldentity;
2153 model_t *model = r_refdef.worldmodel;
2154 unsigned char *data;
2156 // compile the light
2157 rtlight->compiled = true;
2158 rtlight->static_numleafs = 0;
2159 rtlight->static_numleafpvsbytes = 0;
2160 rtlight->static_leaflist = NULL;
2161 rtlight->static_leafpvs = NULL;
2162 rtlight->static_numsurfaces = 0;
2163 rtlight->static_surfacelist = NULL;
2164 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2165 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2166 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2167 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2168 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2169 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2171 if (model && model->GetLightInfo)
2173 // this variable must be set for the CompileShadowVolume code
2174 r_shadow_compilingrtlight = rtlight;
2175 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2176 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2177 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2178 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2179 rtlight->static_numleafs = numleafs;
2180 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2181 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2182 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2183 rtlight->static_numsurfaces = numsurfaces;
2184 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2186 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2187 if (numleafpvsbytes)
2188 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2190 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2191 if (model->CompileShadowVolume && rtlight->shadow)
2192 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2193 // now we're done compiling the rtlight
2194 r_shadow_compilingrtlight = NULL;
2198 // use smallest available cullradius - box radius or light radius
2199 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2200 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2204 if (rtlight->static_meshchain_shadow)
2207 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2210 shadowtris += mesh->numtriangles;
2214 if (developer.integer >= 10)
2215 Con_Printf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes);
2218 void R_RTLight_Uncompile(rtlight_t *rtlight)
2220 if (rtlight->compiled)
2222 if (rtlight->static_meshchain_shadow)
2223 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2224 rtlight->static_meshchain_shadow = NULL;
2225 // these allocations are grouped
2226 if (rtlight->static_leaflist)
2227 Mem_Free(rtlight->static_leaflist);
2228 rtlight->static_numleafs = 0;
2229 rtlight->static_numleafpvsbytes = 0;
2230 rtlight->static_leaflist = NULL;
2231 rtlight->static_leafpvs = NULL;
2232 rtlight->static_numsurfaces = 0;
2233 rtlight->static_surfacelist = NULL;
2234 rtlight->compiled = false;
2238 void R_Shadow_UncompileWorldLights(void)
2241 for (light = r_shadow_worldlightchain;light;light = light->next)
2242 R_RTLight_Uncompile(&light->rtlight);
2245 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2247 model_t *model = ent->model;
2248 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2249 vec_t relativeshadowradius;
2250 if (ent == r_refdef.worldentity)
2252 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2255 R_Mesh_Matrix(&ent->matrix);
2257 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2259 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2260 R_Mesh_VertexPointer(mesh->vertex3f);
2261 GL_LockArrays(0, mesh->numverts);
2262 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2264 // decrement stencil if backface is behind depthbuffer
2265 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2266 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2267 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2268 // increment stencil if frontface is behind depthbuffer
2269 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2270 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2272 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2273 GL_LockArrays(0, 0);
2277 else if (numsurfaces)
2279 R_Mesh_Matrix(&ent->matrix);
2280 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2285 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2286 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2287 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2288 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2289 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2290 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2291 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2292 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2293 R_Mesh_Matrix(&ent->matrix);
2294 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2298 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2300 // set up properties for rendering light onto this entity
2301 RSurf_ActiveEntity(ent, true, true);
2302 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2303 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2304 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2305 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2306 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2307 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2310 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2312 model_t *model = ent->model;
2313 if (!model->DrawLight)
2315 R_Shadow_SetupEntityLight(ent);
2316 if (ent == r_refdef.worldentity)
2317 model->DrawLight(ent, numsurfaces, surfacelist);
2319 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2322 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2326 int numleafs, numsurfaces;
2327 int *leaflist, *surfacelist;
2328 unsigned char *leafpvs;
2329 int numlightentities;
2330 int numshadowentities;
2331 entity_render_t *lightentities[MAX_EDICTS];
2332 entity_render_t *shadowentities[MAX_EDICTS];
2334 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2335 // skip lights that are basically invisible (color 0 0 0)
2336 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2339 // loading is done before visibility checks because loading should happen
2340 // all at once at the start of a level, not when it stalls gameplay.
2341 // (especially important to benchmarks)
2343 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2344 R_RTLight_Compile(rtlight);
2346 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2348 // look up the light style value at this time
2349 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2350 VectorScale(rtlight->color, f, rtlight->currentcolor);
2352 if (rtlight->selected)
2354 f = 2 + sin(realtime * M_PI * 4.0);
2355 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2359 // if lightstyle is currently off, don't draw the light
2360 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2363 // if the light box is offscreen, skip it
2364 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2367 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2369 // compiled light, world available and can receive realtime lighting
2370 // retrieve leaf information
2371 numleafs = rtlight->static_numleafs;
2372 leaflist = rtlight->static_leaflist;
2373 leafpvs = rtlight->static_leafpvs;
2374 numsurfaces = rtlight->static_numsurfaces;
2375 surfacelist = rtlight->static_surfacelist;
2377 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2379 // dynamic light, world available and can receive realtime lighting
2380 // calculate lit surfaces and leafs
2381 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2382 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2383 leaflist = r_shadow_buffer_leaflist;
2384 leafpvs = r_shadow_buffer_leafpvs;
2385 surfacelist = r_shadow_buffer_surfacelist;
2386 // if the reduced leaf bounds are offscreen, skip it
2387 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2399 // check if light is illuminating any visible leafs
2402 for (i = 0;i < numleafs;i++)
2403 if (r_viewcache.world_leafvisible[leaflist[i]])
2408 // set up a scissor rectangle for this light
2409 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2412 // make a list of lit entities and shadow casting entities
2413 numlightentities = 0;
2414 numshadowentities = 0;
2415 // don't count the world unless some surfaces are actually lit
2418 lightentities[numlightentities++] = r_refdef.worldentity;
2419 shadowentities[numshadowentities++] = r_refdef.worldentity;
2421 // add dynamic entities that are lit by the light
2422 if (r_drawentities.integer)
2424 for (i = 0;i < r_refdef.numentities;i++)
2427 entity_render_t *ent = r_refdef.entities[i];
2428 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2429 && (model = ent->model)
2430 && !(ent->flags & RENDER_TRANSPARENT)
2431 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2433 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2435 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2436 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2437 shadowentities[numshadowentities++] = ent;
2438 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2439 lightentities[numlightentities++] = ent;
2444 // return if there's nothing at all to light
2445 if (!numlightentities)
2448 // don't let sound skip if going slow
2449 if (r_refdef.extraupdate)
2452 // make this the active rtlight for rendering purposes
2453 R_Shadow_RenderMode_ActiveLight(rtlight);
2454 // count this light in the r_speeds
2455 r_refdef.stats.lights++;
2458 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2460 // draw stencil shadow volumes to mask off pixels that are in shadow
2461 // so that they won't receive lighting
2465 R_Shadow_RenderMode_StencilShadowVolumes();
2466 for (i = 0;i < numshadowentities;i++)
2467 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2470 // optionally draw visible shape of the shadow volumes
2471 // for performance analysis by level designers
2472 if (r_showshadowvolumes.integer)
2474 R_Shadow_RenderMode_VisibleShadowVolumes();
2475 for (i = 0;i < numshadowentities;i++)
2476 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2480 if (numlightentities)
2482 // draw lighting in the unmasked areas
2483 R_Shadow_RenderMode_Lighting(usestencil, false);
2484 for (i = 0;i < numlightentities;i++)
2485 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2487 // optionally draw the illuminated areas
2488 // for performance analysis by level designers
2489 if (r_showlighting.integer)
2491 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2492 for (i = 0;i < numlightentities;i++)
2493 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2498 void R_ShadowVolumeLighting(qboolean visible)
2503 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2504 R_Shadow_EditLights_Reload_f();
2506 R_Shadow_RenderMode_Begin();
2508 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2509 if (r_shadow_debuglight.integer >= 0)
2511 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2512 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2513 R_DrawRTLight(&light->rtlight, visible);
2516 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2517 if (light->flags & flag)
2518 R_DrawRTLight(&light->rtlight, visible);
2519 if (r_refdef.rtdlight)
2520 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2521 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2523 R_Shadow_RenderMode_End();
2526 extern void R_SetupView(const matrix4x4_t *matrix);
2527 extern cvar_t r_shadows_throwdistance;
2528 void R_DrawModelShadows(void)
2531 float relativethrowdistance;
2532 entity_render_t *ent;
2533 vec3_t relativelightorigin;
2534 vec3_t relativelightdirection;
2535 vec3_t relativeshadowmins, relativeshadowmaxs;
2538 if (!r_drawentities.integer || !gl_stencil)
2542 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2544 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2546 if (gl_ext_stenciltwoside.integer)
2547 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2549 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2551 R_Shadow_RenderMode_StencilShadowVolumes();
2553 for (i = 0;i < r_refdef.numentities;i++)
2555 ent = r_refdef.entities[i];
2556 // cast shadows from anything that is not a submodel of the map
2557 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2559 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2560 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2561 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2562 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2563 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2564 R_Mesh_Matrix(&ent->matrix);
2565 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2569 // not really the right mode, but this will disable any silly stencil features
2570 R_Shadow_RenderMode_VisibleLighting(true, true);
2572 // vertex coordinates for a quad that covers the screen exactly
2573 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2574 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2575 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2576 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2578 // set up ortho view for rendering this pass
2579 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2580 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2581 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2582 GL_ScissorTest(true);
2583 R_Mesh_Matrix(&identitymatrix);
2584 R_Mesh_ResetTextureState();
2585 R_Mesh_VertexPointer(vertex3f);
2586 R_Mesh_ColorPointer(NULL);
2588 // set up a 50% darkening blend on shadowed areas
2589 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2590 GL_DepthTest(false);
2591 GL_DepthMask(false);
2592 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2593 GL_Color(0, 0, 0, 0.5);
2594 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2595 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2596 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2597 qglStencilMask(~0);CHECKGLERROR
2598 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2599 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2601 // apply the blend to the shadowed areas
2602 R_Mesh_Draw(0, 4, 2, polygonelements);
2604 // restore perspective view
2605 R_SetupView(&r_view.matrix);
2607 // restore other state to normal
2609 R_Shadow_RenderMode_End();
2613 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2614 typedef struct suffixinfo_s
2617 qboolean flipx, flipy, flipdiagonal;
2620 static suffixinfo_t suffix[3][6] =
2623 {"px", false, false, false},
2624 {"nx", false, false, false},
2625 {"py", false, false, false},
2626 {"ny", false, false, false},
2627 {"pz", false, false, false},
2628 {"nz", false, false, false}
2631 {"posx", false, false, false},
2632 {"negx", false, false, false},
2633 {"posy", false, false, false},
2634 {"negy", false, false, false},
2635 {"posz", false, false, false},
2636 {"negz", false, false, false}
2639 {"rt", true, false, true},
2640 {"lf", false, true, true},
2641 {"ft", true, true, false},
2642 {"bk", false, false, false},
2643 {"up", true, false, true},
2644 {"dn", true, false, true}
2648 static int componentorder[4] = {0, 1, 2, 3};
2650 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2652 int i, j, cubemapsize;
2653 unsigned char *cubemappixels, *image_rgba;
2654 rtexture_t *cubemaptexture;
2656 // must start 0 so the first loadimagepixels has no requested width/height
2658 cubemappixels = NULL;
2659 cubemaptexture = NULL;
2660 // keep trying different suffix groups (posx, px, rt) until one loads
2661 for (j = 0;j < 3 && !cubemappixels;j++)
2663 // load the 6 images in the suffix group
2664 for (i = 0;i < 6;i++)
2666 // generate an image name based on the base and and suffix
2667 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2669 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2671 // an image loaded, make sure width and height are equal
2672 if (image_width == image_height)
2674 // if this is the first image to load successfully, allocate the cubemap memory
2675 if (!cubemappixels && image_width >= 1)
2677 cubemapsize = image_width;
2678 // note this clears to black, so unavailable sides are black
2679 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2681 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2683 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);
2686 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2688 Mem_Free(image_rgba);
2692 // if a cubemap loaded, upload it
2695 if (!r_shadow_filters_texturepool)
2696 r_shadow_filters_texturepool = R_AllocTexturePool();
2697 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2698 Mem_Free(cubemappixels);
2702 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2703 for (j = 0;j < 3;j++)
2704 for (i = 0;i < 6;i++)
2705 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2706 Con_Print(" and was unable to find any of them.\n");
2708 return cubemaptexture;
2711 rtexture_t *R_Shadow_Cubemap(const char *basename)
2714 for (i = 0;i < numcubemaps;i++)
2715 if (!strcasecmp(cubemaps[i].basename, basename))
2716 return cubemaps[i].texture;
2717 if (i >= MAX_CUBEMAPS)
2718 return r_texture_whitecube;
2720 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2721 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2722 if (!cubemaps[i].texture)
2723 cubemaps[i].texture = r_texture_whitecube;
2724 return cubemaps[i].texture;
2727 void R_Shadow_FreeCubemaps(void)
2730 R_FreeTexturePool(&r_shadow_filters_texturepool);
2733 dlight_t *R_Shadow_NewWorldLight(void)
2736 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2737 light->next = r_shadow_worldlightchain;
2738 r_shadow_worldlightchain = light;
2742 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)
2744 VectorCopy(origin, light->origin);
2745 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2746 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2747 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2748 light->color[0] = max(color[0], 0);
2749 light->color[1] = max(color[1], 0);
2750 light->color[2] = max(color[2], 0);
2751 light->radius = max(radius, 0);
2752 light->style = style;
2753 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2755 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2758 light->shadow = shadowenable;
2759 light->corona = corona;
2762 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2763 light->coronasizescale = coronasizescale;
2764 light->ambientscale = ambientscale;
2765 light->diffusescale = diffusescale;
2766 light->specularscale = specularscale;
2767 light->flags = flags;
2768 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2770 R_RTLight_Update(light, true);
2773 void R_Shadow_FreeWorldLight(dlight_t *light)
2775 dlight_t **lightpointer;
2776 R_RTLight_Uncompile(&light->rtlight);
2777 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2778 if (*lightpointer != light)
2779 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2780 *lightpointer = light->next;
2784 void R_Shadow_ClearWorldLights(void)
2786 while (r_shadow_worldlightchain)
2787 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2788 r_shadow_selectedlight = NULL;
2789 R_Shadow_FreeCubemaps();
2792 void R_Shadow_SelectLight(dlight_t *light)
2794 if (r_shadow_selectedlight)
2795 r_shadow_selectedlight->selected = false;
2796 r_shadow_selectedlight = light;
2797 if (r_shadow_selectedlight)
2798 r_shadow_selectedlight->selected = true;
2801 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2803 // this is never batched (there can be only one)
2804 float scale = r_editlights_cursorgrid.value * 0.5f;
2805 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2808 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2810 // this is never batched (due to the ent parameter changing every time)
2811 // so numsurfaces == 1 and surfacelist[0] == lightnumber
2813 const dlight_t *light = (dlight_t *)ent;
2815 if (light->selected)
2816 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2819 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2822 void R_Shadow_DrawLightSprites(void)
2827 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2828 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2829 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2832 void R_Shadow_SelectLightInView(void)
2834 float bestrating, rating, temp[3];
2835 dlight_t *best, *light;
2838 for (light = r_shadow_worldlightchain;light;light = light->next)
2840 VectorSubtract(light->origin, r_view.origin, temp);
2841 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2844 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2845 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2847 bestrating = rating;
2852 R_Shadow_SelectLight(best);
2855 void R_Shadow_LoadWorldLights(void)
2857 int n, a, style, shadow, flags;
2858 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2859 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2860 if (r_refdef.worldmodel == NULL)
2862 Con_Print("No map loaded.\n");
2865 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2866 strlcat (name, ".rtlights", sizeof (name));
2867 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2877 for (;COM_Parse(t, true) && strcmp(
2878 if (COM_Parse(t, true))
2880 if (com_token[0] == '!')
2883 origin[0] = atof(com_token+1);
2886 origin[0] = atof(com_token);
2891 while (*s && *s != '\n' && *s != '\r')
2897 // check for modifier flags
2904 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);
2907 flags = LIGHTFLAG_REALTIMEMODE;
2915 coronasizescale = 0.25f;
2917 VectorClear(angles);
2920 if (a < 9 || !strcmp(cubemapname, "\"\""))
2922 // remove quotes on cubemapname
2923 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2926 namelen = strlen(cubemapname) - 2;
2927 memmove(cubemapname, cubemapname + 1, namelen);
2928 cubemapname[namelen] = '\0';
2932 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);
2935 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2943 Con_Printf("invalid rtlights file \"%s\"\n", name);
2944 Mem_Free(lightsstring);
2948 void R_Shadow_SaveWorldLights(void)
2951 size_t bufchars, bufmaxchars;
2953 char name[MAX_QPATH];
2954 char line[MAX_INPUTLINE];
2955 if (!r_shadow_worldlightchain)
2957 if (r_refdef.worldmodel == NULL)
2959 Con_Print("No map loaded.\n");
2962 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2963 strlcat (name, ".rtlights", sizeof (name));
2964 bufchars = bufmaxchars = 0;
2966 for (light = r_shadow_worldlightchain;light;light = light->next)
2968 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2969 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
2970 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2971 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
2973 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style);
2974 if (bufchars + strlen(line) > bufmaxchars)
2976 bufmaxchars = bufchars + strlen(line) + 2048;
2978 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2982 memcpy(buf, oldbuf, bufchars);
2988 memcpy(buf + bufchars, line, strlen(line));
2989 bufchars += strlen(line);
2993 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2998 void R_Shadow_LoadLightsFile(void)
3001 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3002 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3003 if (r_refdef.worldmodel == NULL)
3005 Con_Print("No map loaded.\n");
3008 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3009 strlcat (name, ".lights", sizeof (name));
3010 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3018 while (*s && *s != '\n' && *s != '\r')
3024 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);
3028 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);
3031 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3032 radius = bound(15, radius, 4096);
3033 VectorScale(color, (2.0f / (8388608.0f)), color);
3034 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3042 Con_Printf("invalid lights file \"%s\"\n", name);
3043 Mem_Free(lightsstring);
3047 // tyrlite/hmap2 light types in the delay field
3048 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3050 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3052 int entnum, style, islight, skin, pflags, effects, type, n;
3055 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3056 char key[256], value[MAX_INPUTLINE];
3058 if (r_refdef.worldmodel == NULL)
3060 Con_Print("No map loaded.\n");
3063 // try to load a .ent file first
3064 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3065 strlcat (key, ".ent", sizeof (key));
3066 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3067 // and if that is not found, fall back to the bsp file entity string
3069 data = r_refdef.worldmodel->brush.entities;
3072 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3074 type = LIGHTTYPE_MINUSX;
3075 origin[0] = origin[1] = origin[2] = 0;
3076 originhack[0] = originhack[1] = originhack[2] = 0;
3077 angles[0] = angles[1] = angles[2] = 0;
3078 color[0] = color[1] = color[2] = 1;
3079 light[0] = light[1] = light[2] = 1;light[3] = 300;
3080 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3090 if (!COM_ParseTokenConsole(&data))
3092 if (com_token[0] == '}')
3093 break; // end of entity
3094 if (com_token[0] == '_')
3095 strlcpy(key, com_token + 1, sizeof(key));
3097 strlcpy(key, com_token, sizeof(key));
3098 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3099 key[strlen(key)-1] = 0;
3100 if (!COM_ParseTokenConsole(&data))
3102 strlcpy(value, com_token, sizeof(value));
3104 // now that we have the key pair worked out...
3105 if (!strcmp("light", key))
3107 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3111 light[0] = vec[0] * (1.0f / 256.0f);
3112 light[1] = vec[0] * (1.0f / 256.0f);
3113 light[2] = vec[0] * (1.0f / 256.0f);
3119 light[0] = vec[0] * (1.0f / 255.0f);
3120 light[1] = vec[1] * (1.0f / 255.0f);
3121 light[2] = vec[2] * (1.0f / 255.0f);
3125 else if (!strcmp("delay", key))
3127 else if (!strcmp("origin", key))
3128 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3129 else if (!strcmp("angle", key))
3130 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3131 else if (!strcmp("angles", key))
3132 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3133 else if (!strcmp("color", key))
3134 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3135 else if (!strcmp("wait", key))
3136 fadescale = atof(value);
3137 else if (!strcmp("classname", key))
3139 if (!strncmp(value, "light", 5))
3142 if (!strcmp(value, "light_fluoro"))
3147 overridecolor[0] = 1;
3148 overridecolor[1] = 1;
3149 overridecolor[2] = 1;
3151 if (!strcmp(value, "light_fluorospark"))
3156 overridecolor[0] = 1;
3157 overridecolor[1] = 1;
3158 overridecolor[2] = 1;
3160 if (!strcmp(value, "light_globe"))
3165 overridecolor[0] = 1;
3166 overridecolor[1] = 0.8;
3167 overridecolor[2] = 0.4;
3169 if (!strcmp(value, "light_flame_large_yellow"))
3174 overridecolor[0] = 1;
3175 overridecolor[1] = 0.5;
3176 overridecolor[2] = 0.1;
3178 if (!strcmp(value, "light_flame_small_yellow"))
3183 overridecolor[0] = 1;
3184 overridecolor[1] = 0.5;
3185 overridecolor[2] = 0.1;
3187 if (!strcmp(value, "light_torch_small_white"))
3192 overridecolor[0] = 1;
3193 overridecolor[1] = 0.5;
3194 overridecolor[2] = 0.1;
3196 if (!strcmp(value, "light_torch_small_walltorch"))
3201 overridecolor[0] = 1;
3202 overridecolor[1] = 0.5;
3203 overridecolor[2] = 0.1;
3207 else if (!strcmp("style", key))
3208 style = atoi(value);
3209 else if (!strcmp("skin", key))
3210 skin = (int)atof(value);
3211 else if (!strcmp("pflags", key))
3212 pflags = (int)atof(value);
3213 else if (!strcmp("effects", key))
3214 effects = (int)atof(value);
3215 else if (r_refdef.worldmodel->type == mod_brushq3)
3217 if (!strcmp("scale", key))
3218 lightscale = atof(value);
3219 if (!strcmp("fade", key))
3220 fadescale = atof(value);
3225 if (lightscale <= 0)
3229 if (color[0] == color[1] && color[0] == color[2])
3231 color[0] *= overridecolor[0];
3232 color[1] *= overridecolor[1];
3233 color[2] *= overridecolor[2];
3235 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3236 color[0] = color[0] * light[0];
3237 color[1] = color[1] * light[1];
3238 color[2] = color[2] * light[2];
3241 case LIGHTTYPE_MINUSX:
3243 case LIGHTTYPE_RECIPX:
3245 VectorScale(color, (1.0f / 16.0f), color);
3247 case LIGHTTYPE_RECIPXX:
3249 VectorScale(color, (1.0f / 16.0f), color);
3252 case LIGHTTYPE_NONE:
3256 case LIGHTTYPE_MINUSXX:
3259 VectorAdd(origin, originhack, origin);
3261 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);
3264 Mem_Free(entfiledata);
3268 void R_Shadow_SetCursorLocationForView(void)
3271 vec3_t dest, endpos;
3273 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3274 trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3275 if (trace.fraction < 1)
3277 dist = trace.fraction * r_editlights_cursordistance.value;
3278 push = r_editlights_cursorpushback.value;
3282 VectorMA(trace.endpos, push, r_view.forward, endpos);
3283 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3287 VectorClear( endpos );
3289 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3290 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3291 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3294 void R_Shadow_UpdateWorldLightSelection(void)
3296 if (r_editlights.integer)
3298 R_Shadow_SetCursorLocationForView();
3299 R_Shadow_SelectLightInView();
3300 R_Shadow_DrawLightSprites();
3303 R_Shadow_SelectLight(NULL);
3306 void R_Shadow_EditLights_Clear_f(void)
3308 R_Shadow_ClearWorldLights();
3311 void R_Shadow_EditLights_Reload_f(void)
3313 if (!r_refdef.worldmodel)
3315 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3316 R_Shadow_ClearWorldLights();
3317 R_Shadow_LoadWorldLights();
3318 if (r_shadow_worldlightchain == NULL)
3320 R_Shadow_LoadLightsFile();
3321 if (r_shadow_worldlightchain == NULL)
3322 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3326 void R_Shadow_EditLights_Save_f(void)
3328 if (!r_refdef.worldmodel)
3330 R_Shadow_SaveWorldLights();
3333 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3335 R_Shadow_ClearWorldLights();
3336 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3339 void R_Shadow_EditLights_ImportLightsFile_f(void)
3341 R_Shadow_ClearWorldLights();
3342 R_Shadow_LoadLightsFile();
3345 void R_Shadow_EditLights_Spawn_f(void)
3348 if (!r_editlights.integer)
3350 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3353 if (Cmd_Argc() != 1)
3355 Con_Print("r_editlights_spawn does not take parameters\n");
3358 color[0] = color[1] = color[2] = 1;
3359 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3362 void R_Shadow_EditLights_Edit_f(void)
3364 vec3_t origin, angles, color;
3365 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3366 int style, shadows, flags, normalmode, realtimemode;
3367 char cubemapname[MAX_INPUTLINE];
3368 if (!r_editlights.integer)
3370 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3373 if (!r_shadow_selectedlight)
3375 Con_Print("No selected light.\n");
3378 VectorCopy(r_shadow_selectedlight->origin, origin);
3379 VectorCopy(r_shadow_selectedlight->angles, angles);
3380 VectorCopy(r_shadow_selectedlight->color, color);
3381 radius = r_shadow_selectedlight->radius;
3382 style = r_shadow_selectedlight->style;
3383 if (r_shadow_selectedlight->cubemapname)
3384 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3387 shadows = r_shadow_selectedlight->shadow;
3388 corona = r_shadow_selectedlight->corona;
3389 coronasizescale = r_shadow_selectedlight->coronasizescale;
3390 ambientscale = r_shadow_selectedlight->ambientscale;
3391 diffusescale = r_shadow_selectedlight->diffusescale;
3392 specularscale = r_shadow_selectedlight->specularscale;
3393 flags = r_shadow_selectedlight->flags;
3394 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3395 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3396 if (!strcmp(Cmd_Argv(1), "origin"))
3398 if (Cmd_Argc() != 5)
3400 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3403 origin[0] = atof(Cmd_Argv(2));
3404 origin[1] = atof(Cmd_Argv(3));
3405 origin[2] = atof(Cmd_Argv(4));
3407 else if (!strcmp(Cmd_Argv(1), "originx"))
3409 if (Cmd_Argc() != 3)
3411 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3414 origin[0] = atof(Cmd_Argv(2));
3416 else if (!strcmp(Cmd_Argv(1), "originy"))
3418 if (Cmd_Argc() != 3)
3420 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3423 origin[1] = atof(Cmd_Argv(2));
3425 else if (!strcmp(Cmd_Argv(1), "originz"))
3427 if (Cmd_Argc() != 3)
3429 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3432 origin[2] = atof(Cmd_Argv(2));
3434 else if (!strcmp(Cmd_Argv(1), "move"))
3436 if (Cmd_Argc() != 5)
3438 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3441 origin[0] += atof(Cmd_Argv(2));
3442 origin[1] += atof(Cmd_Argv(3));
3443 origin[2] += atof(Cmd_Argv(4));
3445 else if (!strcmp(Cmd_Argv(1), "movex"))
3447 if (Cmd_Argc() != 3)
3449 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3452 origin[0] += atof(Cmd_Argv(2));
3454 else if (!strcmp(Cmd_Argv(1), "movey"))
3456 if (Cmd_Argc() != 3)
3458 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3461 origin[1] += atof(Cmd_Argv(2));
3463 else if (!strcmp(Cmd_Argv(1), "movez"))
3465 if (Cmd_Argc() != 3)
3467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3470 origin[2] += atof(Cmd_Argv(2));
3472 else if (!strcmp(Cmd_Argv(1), "angles"))
3474 if (Cmd_Argc() != 5)
3476 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3479 angles[0] = atof(Cmd_Argv(2));
3480 angles[1] = atof(Cmd_Argv(3));
3481 angles[2] = atof(Cmd_Argv(4));
3483 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3485 if (Cmd_Argc() != 3)
3487 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3490 angles[0] = atof(Cmd_Argv(2));
3492 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3494 if (Cmd_Argc() != 3)
3496 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3499 angles[1] = atof(Cmd_Argv(2));
3501 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3503 if (Cmd_Argc() != 3)
3505 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3508 angles[2] = atof(Cmd_Argv(2));
3510 else if (!strcmp(Cmd_Argv(1), "color"))
3512 if (Cmd_Argc() != 5)
3514 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3517 color[0] = atof(Cmd_Argv(2));
3518 color[1] = atof(Cmd_Argv(3));
3519 color[2] = atof(Cmd_Argv(4));
3521 else if (!strcmp(Cmd_Argv(1), "radius"))
3523 if (Cmd_Argc() != 3)
3525 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3528 radius = atof(Cmd_Argv(2));
3530 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3532 if (Cmd_Argc() == 3)
3534 double scale = atof(Cmd_Argv(2));
3541 if (Cmd_Argc() != 5)
3543 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3546 color[0] *= atof(Cmd_Argv(2));
3547 color[1] *= atof(Cmd_Argv(3));
3548 color[2] *= atof(Cmd_Argv(4));
3551 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3553 if (Cmd_Argc() != 3)
3555 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3558 radius *= atof(Cmd_Argv(2));
3560 else if (!strcmp(Cmd_Argv(1), "style"))
3562 if (Cmd_Argc() != 3)
3564 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3567 style = atoi(Cmd_Argv(2));
3569 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3573 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3576 if (Cmd_Argc() == 3)
3577 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3581 else if (!strcmp(Cmd_Argv(1), "shadows"))
3583 if (Cmd_Argc() != 3)
3585 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3588 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3590 else if (!strcmp(Cmd_Argv(1), "corona"))
3592 if (Cmd_Argc() != 3)
3594 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3597 corona = atof(Cmd_Argv(2));
3599 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3601 if (Cmd_Argc() != 3)
3603 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3606 coronasizescale = atof(Cmd_Argv(2));
3608 else if (!strcmp(Cmd_Argv(1), "ambient"))
3610 if (Cmd_Argc() != 3)
3612 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3615 ambientscale = atof(Cmd_Argv(2));
3617 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3619 if (Cmd_Argc() != 3)
3621 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3624 diffusescale = atof(Cmd_Argv(2));
3626 else if (!strcmp(Cmd_Argv(1), "specular"))
3628 if (Cmd_Argc() != 3)
3630 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3633 specularscale = atof(Cmd_Argv(2));
3635 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3637 if (Cmd_Argc() != 3)
3639 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3642 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3644 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3646 if (Cmd_Argc() != 3)
3648 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3651 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3655 Con_Print("usage: r_editlights_edit [property] [value]\n");
3656 Con_Print("Selected light's properties:\n");
3657 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3658 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3659 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3660 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3661 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3662 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3663 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3664 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3665 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3666 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3667 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3668 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3669 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3670 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3673 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3674 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3677 void R_Shadow_EditLights_EditAll_f(void)
3681 if (!r_editlights.integer)
3683 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3687 for (light = r_shadow_worldlightchain;light;light = light->next)
3689 R_Shadow_SelectLight(light);
3690 R_Shadow_EditLights_Edit_f();
3694 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3696 int lightnumber, lightcount;
3700 if (!r_editlights.integer)
3706 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3707 if (light == r_shadow_selectedlight)
3708 lightnumber = lightcount;
3709 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;
3710 if (r_shadow_selectedlight == NULL)
3712 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3713 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;
3714 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;
3715 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;
3716 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3717 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3718 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3719 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;
3720 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3721 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3722 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3723 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3724 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3725 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;
3726 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;
3729 void R_Shadow_EditLights_ToggleShadow_f(void)
3731 if (!r_editlights.integer)
3733 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3736 if (!r_shadow_selectedlight)
3738 Con_Print("No selected light.\n");
3741 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);
3744 void R_Shadow_EditLights_ToggleCorona_f(void)
3746 if (!r_editlights.integer)
3748 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3751 if (!r_shadow_selectedlight)
3753 Con_Print("No selected light.\n");
3756 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);
3759 void R_Shadow_EditLights_Remove_f(void)
3761 if (!r_editlights.integer)
3763 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3766 if (!r_shadow_selectedlight)
3768 Con_Print("No selected light.\n");
3771 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3772 r_shadow_selectedlight = NULL;
3775 void R_Shadow_EditLights_Help_f(void)
3778 "Documentation on r_editlights system:\n"
3780 "r_editlights : enable/disable editing mode\n"
3781 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3782 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3783 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3784 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3785 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3787 "r_editlights_help : this help\n"
3788 "r_editlights_clear : remove all lights\n"
3789 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3790 "r_editlights_save : save to .rtlights file\n"
3791 "r_editlights_spawn : create a light with default settings\n"
3792 "r_editlights_edit command : edit selected light - more documentation below\n"
3793 "r_editlights_remove : remove selected light\n"
3794 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3795 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3796 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3798 "origin x y z : set light location\n"
3799 "originx x: set x component of light location\n"
3800 "originy y: set y component of light location\n"
3801 "originz z: set z component of light location\n"
3802 "move x y z : adjust light location\n"
3803 "movex x: adjust x component of light location\n"
3804 "movey y: adjust y component of light location\n"
3805 "movez z: adjust z component of light location\n"
3806 "angles x y z : set light angles\n"
3807 "anglesx x: set x component of light angles\n"
3808 "anglesy y: set y component of light angles\n"
3809 "anglesz z: set z component of light angles\n"
3810 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3811 "radius radius : set radius (size) of light\n"
3812 "colorscale grey : multiply color of light (1 does nothing)\n"
3813 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3814 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3815 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3816 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3817 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3818 "shadows 1/0 : turn on/off shadows\n"
3819 "corona n : set corona intensity\n"
3820 "coronasize n : set corona size (0-1)\n"
3821 "ambient n : set ambient intensity (0-1)\n"
3822 "diffuse n : set diffuse intensity (0-1)\n"
3823 "specular n : set specular intensity (0-1)\n"
3824 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3825 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3826 "<nothing> : print light properties to console\n"
3830 void R_Shadow_EditLights_CopyInfo_f(void)
3832 if (!r_editlights.integer)
3834 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3837 if (!r_shadow_selectedlight)
3839 Con_Print("No selected light.\n");
3842 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3843 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3844 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3845 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3846 if (r_shadow_selectedlight->cubemapname)
3847 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3849 r_shadow_bufferlight.cubemapname[0] = 0;
3850 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3851 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3852 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3853 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3854 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3855 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3856 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3859 void R_Shadow_EditLights_PasteInfo_f(void)
3861 if (!r_editlights.integer)
3863 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3866 if (!r_shadow_selectedlight)
3868 Con_Print("No selected light.\n");
3871 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);
3874 void R_Shadow_EditLights_Init(void)
3876 Cvar_RegisterVariable(&r_editlights);
3877 Cvar_RegisterVariable(&r_editlights_cursordistance);
3878 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3879 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3880 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3881 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3882 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3883 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3884 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
3885 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3886 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3887 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3888 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f, "changes a property on ALL lights at once (tip: use radiusscale and colorscale to alter these properties)");
3889 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3890 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3891 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3892 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3893 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3894 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3895 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");