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.5", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
202 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "2", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
203 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
204 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
205 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
206 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
207 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
208 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
209 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
210 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
211 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!)"};
212 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)"};
213 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"};
214 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"};
215 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
216 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
217 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"};
218 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)"};
219 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
220 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)"};
221 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)"};
222 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
223 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
224 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
225 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
226 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
227 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
228 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
230 float r_shadow_attenpower, r_shadow_attenscale;
232 rtlight_t *r_shadow_compilingrtlight;
233 dlight_t *r_shadow_worldlightchain;
234 dlight_t *r_shadow_selectedlight;
235 dlight_t r_shadow_bufferlight;
236 vec3_t r_editlights_cursorlocation;
238 extern int con_vislines;
240 typedef struct cubemapinfo_s
247 #define MAX_CUBEMAPS 256
248 static int numcubemaps;
249 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
251 void R_Shadow_UncompileWorldLights(void);
252 void R_Shadow_ClearWorldLights(void);
253 void R_Shadow_SaveWorldLights(void);
254 void R_Shadow_LoadWorldLights(void);
255 void R_Shadow_LoadLightsFile(void);
256 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
257 void R_Shadow_EditLights_Reload_f(void);
258 void R_Shadow_ValidateCvars(void);
259 static void R_Shadow_MakeTextures(void);
260 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
262 void r_shadow_start(void)
264 // allocate vertex processing arrays
266 r_shadow_attenuation2dtexture = NULL;
267 r_shadow_attenuation3dtexture = NULL;
268 r_shadow_texturepool = NULL;
269 r_shadow_filters_texturepool = NULL;
270 R_Shadow_ValidateCvars();
271 R_Shadow_MakeTextures();
272 maxshadowtriangles = 0;
273 shadowelements = NULL;
274 maxshadowvertices = 0;
275 shadowvertex3f = NULL;
283 shadowmarklist = NULL;
285 r_shadow_buffer_numleafpvsbytes = 0;
286 r_shadow_buffer_leafpvs = NULL;
287 r_shadow_buffer_leaflist = NULL;
288 r_shadow_buffer_numsurfacepvsbytes = 0;
289 r_shadow_buffer_surfacepvs = NULL;
290 r_shadow_buffer_surfacelist = NULL;
293 void r_shadow_shutdown(void)
295 R_Shadow_UncompileWorldLights();
297 r_shadow_attenuation2dtexture = NULL;
298 r_shadow_attenuation3dtexture = NULL;
299 R_FreeTexturePool(&r_shadow_texturepool);
300 R_FreeTexturePool(&r_shadow_filters_texturepool);
301 maxshadowtriangles = 0;
303 Mem_Free(shadowelements);
304 shadowelements = NULL;
306 Mem_Free(shadowvertex3f);
307 shadowvertex3f = NULL;
310 Mem_Free(vertexupdate);
313 Mem_Free(vertexremap);
319 Mem_Free(shadowmark);
322 Mem_Free(shadowmarklist);
323 shadowmarklist = NULL;
325 r_shadow_buffer_numleafpvsbytes = 0;
326 if (r_shadow_buffer_leafpvs)
327 Mem_Free(r_shadow_buffer_leafpvs);
328 r_shadow_buffer_leafpvs = NULL;
329 if (r_shadow_buffer_leaflist)
330 Mem_Free(r_shadow_buffer_leaflist);
331 r_shadow_buffer_leaflist = NULL;
332 r_shadow_buffer_numsurfacepvsbytes = 0;
333 if (r_shadow_buffer_surfacepvs)
334 Mem_Free(r_shadow_buffer_surfacepvs);
335 r_shadow_buffer_surfacepvs = NULL;
336 if (r_shadow_buffer_surfacelist)
337 Mem_Free(r_shadow_buffer_surfacelist);
338 r_shadow_buffer_surfacelist = NULL;
341 void r_shadow_newmap(void)
345 void R_Shadow_Help_f(void)
348 "Documentation on r_shadow system:\n"
350 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
351 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
352 "r_shadow_debuglight : render only this light number (-1 = all)\n"
353 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
354 "r_shadow_gloss2intensity : brightness of forced gloss\n"
355 "r_shadow_glossintensity : brightness of textured gloss\n"
356 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
357 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
358 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
359 "r_shadow_portallight : use portal visibility for static light precomputation\n"
360 "r_shadow_projectdistance : shadow volume projection distance\n"
361 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
362 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
363 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
364 "r_shadow_realtime_world : use high quality world lighting mode\n"
365 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
366 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
367 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
368 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
369 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
370 "r_shadow_scissor : use scissor optimization\n"
371 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
372 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
373 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
374 "r_showlighting : useful for performance testing; bright = slow!\n"
375 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
377 "r_shadow_help : this help\n"
381 void R_Shadow_Init(void)
383 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
384 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
385 Cvar_RegisterVariable(&r_shadow_debuglight);
386 Cvar_RegisterVariable(&r_shadow_gloss);
387 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
388 Cvar_RegisterVariable(&r_shadow_glossintensity);
389 Cvar_RegisterVariable(&r_shadow_glossexponent);
390 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
391 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
392 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
393 Cvar_RegisterVariable(&r_shadow_portallight);
394 Cvar_RegisterVariable(&r_shadow_projectdistance);
395 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
396 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
397 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
398 Cvar_RegisterVariable(&r_shadow_realtime_world);
399 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
400 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
401 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
402 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
403 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
404 Cvar_RegisterVariable(&r_shadow_scissor);
405 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
406 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
407 Cvar_RegisterVariable(&r_shadow_texture3d);
408 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
409 if (gamemode == GAME_TENEBRAE)
411 Cvar_SetValue("r_shadow_gloss", 2);
412 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
414 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
415 R_Shadow_EditLights_Init();
416 r_shadow_worldlightchain = NULL;
417 maxshadowtriangles = 0;
418 shadowelements = NULL;
419 maxshadowvertices = 0;
420 shadowvertex3f = NULL;
428 shadowmarklist = NULL;
430 r_shadow_buffer_numleafpvsbytes = 0;
431 r_shadow_buffer_leafpvs = NULL;
432 r_shadow_buffer_leaflist = NULL;
433 r_shadow_buffer_numsurfacepvsbytes = 0;
434 r_shadow_buffer_surfacepvs = NULL;
435 r_shadow_buffer_surfacelist = NULL;
436 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
439 matrix4x4_t matrix_attenuationxyz =
442 {0.5, 0.0, 0.0, 0.5},
443 {0.0, 0.5, 0.0, 0.5},
444 {0.0, 0.0, 0.5, 0.5},
449 matrix4x4_t matrix_attenuationz =
452 {0.0, 0.0, 0.5, 0.5},
453 {0.0, 0.0, 0.0, 0.5},
454 {0.0, 0.0, 0.0, 0.5},
459 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
461 // make sure shadowelements is big enough for this volume
462 if (maxshadowtriangles < numtriangles)
464 maxshadowtriangles = numtriangles;
466 Mem_Free(shadowelements);
467 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
469 // make sure shadowvertex3f is big enough for this volume
470 if (maxshadowvertices < numvertices)
472 maxshadowvertices = numvertices;
474 Mem_Free(shadowvertex3f);
475 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
479 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
481 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
482 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
483 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
485 if (r_shadow_buffer_leafpvs)
486 Mem_Free(r_shadow_buffer_leafpvs);
487 if (r_shadow_buffer_leaflist)
488 Mem_Free(r_shadow_buffer_leaflist);
489 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
490 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
491 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
493 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
495 if (r_shadow_buffer_surfacepvs)
496 Mem_Free(r_shadow_buffer_surfacepvs);
497 if (r_shadow_buffer_surfacelist)
498 Mem_Free(r_shadow_buffer_surfacelist);
499 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
500 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
501 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
505 void R_Shadow_PrepareShadowMark(int numtris)
507 // make sure shadowmark is big enough for this volume
508 if (maxshadowmark < numtris)
510 maxshadowmark = numtris;
512 Mem_Free(shadowmark);
514 Mem_Free(shadowmarklist);
515 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
516 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
520 // if shadowmarkcount wrapped we clear the array and adjust accordingly
521 if (shadowmarkcount == 0)
524 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
529 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)
532 int outtriangles = 0, outvertices = 0;
535 float ratio, direction[3], projectvector[3];
537 if (projectdirection)
538 VectorScale(projectdirection, projectdistance, projectvector);
540 VectorClear(projectvector);
542 if (maxvertexupdate < innumvertices)
544 maxvertexupdate = innumvertices;
546 Mem_Free(vertexupdate);
548 Mem_Free(vertexremap);
549 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
550 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
554 if (vertexupdatenum == 0)
557 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
558 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
561 for (i = 0;i < numshadowmarktris;i++)
562 shadowmark[shadowmarktris[i]] = shadowmarkcount;
564 // create the vertices
565 if (projectdirection)
567 for (i = 0;i < numshadowmarktris;i++)
569 element = inelement3i + shadowmarktris[i] * 3;
570 for (j = 0;j < 3;j++)
572 if (vertexupdate[element[j]] != vertexupdatenum)
574 vertexupdate[element[j]] = vertexupdatenum;
575 vertexremap[element[j]] = outvertices;
576 vertex = invertex3f + element[j] * 3;
577 // project one copy of the vertex according to projectvector
578 VectorCopy(vertex, outvertex3f);
579 VectorAdd(vertex, projectvector, (outvertex3f + 3));
588 for (i = 0;i < numshadowmarktris;i++)
590 element = inelement3i + shadowmarktris[i] * 3;
591 for (j = 0;j < 3;j++)
593 if (vertexupdate[element[j]] != vertexupdatenum)
595 vertexupdate[element[j]] = vertexupdatenum;
596 vertexremap[element[j]] = outvertices;
597 vertex = invertex3f + element[j] * 3;
598 // project one copy of the vertex to the sphere radius of the light
599 // (FIXME: would projecting it to the light box be better?)
600 VectorSubtract(vertex, projectorigin, direction);
601 ratio = projectdistance / VectorLength(direction);
602 VectorCopy(vertex, outvertex3f);
603 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
611 for (i = 0;i < numshadowmarktris;i++)
613 int remappedelement[3];
615 const int *neighbortriangle;
617 markindex = shadowmarktris[i] * 3;
618 element = inelement3i + markindex;
619 neighbortriangle = inneighbor3i + markindex;
620 // output the front and back triangles
621 outelement3i[0] = vertexremap[element[0]];
622 outelement3i[1] = vertexremap[element[1]];
623 outelement3i[2] = vertexremap[element[2]];
624 outelement3i[3] = vertexremap[element[2]] + 1;
625 outelement3i[4] = vertexremap[element[1]] + 1;
626 outelement3i[5] = vertexremap[element[0]] + 1;
630 // output the sides (facing outward from this triangle)
631 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
633 remappedelement[0] = vertexremap[element[0]];
634 remappedelement[1] = vertexremap[element[1]];
635 outelement3i[0] = remappedelement[1];
636 outelement3i[1] = remappedelement[0];
637 outelement3i[2] = remappedelement[0] + 1;
638 outelement3i[3] = remappedelement[1];
639 outelement3i[4] = remappedelement[0] + 1;
640 outelement3i[5] = remappedelement[1] + 1;
645 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
647 remappedelement[1] = vertexremap[element[1]];
648 remappedelement[2] = vertexremap[element[2]];
649 outelement3i[0] = remappedelement[2];
650 outelement3i[1] = remappedelement[1];
651 outelement3i[2] = remappedelement[1] + 1;
652 outelement3i[3] = remappedelement[2];
653 outelement3i[4] = remappedelement[1] + 1;
654 outelement3i[5] = remappedelement[2] + 1;
659 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
661 remappedelement[0] = vertexremap[element[0]];
662 remappedelement[2] = vertexremap[element[2]];
663 outelement3i[0] = remappedelement[0];
664 outelement3i[1] = remappedelement[2];
665 outelement3i[2] = remappedelement[2] + 1;
666 outelement3i[3] = remappedelement[0];
667 outelement3i[4] = remappedelement[2] + 1;
668 outelement3i[5] = remappedelement[0] + 1;
675 *outnumvertices = outvertices;
679 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)
682 if (projectdistance < 0.1)
684 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
687 if (!numverts || !nummarktris)
689 // make sure shadowelements is big enough for this volume
690 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
691 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
692 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
693 r_refdef.stats.lights_dynamicshadowtriangles += tris;
694 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
697 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)
703 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
705 tend = firsttriangle + numtris;
706 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
707 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
708 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
710 // surface box entirely inside light box, no box cull
711 if (projectdirection)
713 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
715 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
716 if (DotProduct(normal, projectdirection) < 0)
717 shadowmarklist[numshadowmark++] = t;
722 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
723 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
724 shadowmarklist[numshadowmark++] = t;
729 // surface box not entirely inside light box, cull each triangle
730 if (projectdirection)
732 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
734 v[0] = invertex3f + e[0] * 3;
735 v[1] = invertex3f + e[1] * 3;
736 v[2] = invertex3f + e[2] * 3;
737 TriangleNormal(v[0], v[1], v[2], normal);
738 if (DotProduct(normal, projectdirection) < 0
739 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
740 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
741 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
742 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
743 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
744 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
745 shadowmarklist[numshadowmark++] = t;
750 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
752 v[0] = invertex3f + e[0] * 3;
753 v[1] = invertex3f + e[1] * 3;
754 v[2] = invertex3f + e[2] * 3;
755 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
756 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
757 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
758 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
759 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
760 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
761 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
762 shadowmarklist[numshadowmark++] = t;
768 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
770 if (r_shadow_compilingrtlight)
772 // if we're compiling an rtlight, capture the mesh
773 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
776 r_refdef.stats.lights_shadowtriangles += numtriangles;
778 R_Mesh_VertexPointer(vertex3f);
779 GL_LockArrays(0, numvertices);
780 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
782 // decrement stencil if backface is behind depthbuffer
783 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
784 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
785 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
786 // increment stencil if frontface is behind depthbuffer
787 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
788 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
790 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
795 static void R_Shadow_MakeTextures(void)
798 float v[3], intensity;
800 R_FreeTexturePool(&r_shadow_texturepool);
801 r_shadow_texturepool = R_AllocTexturePool();
802 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
803 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
804 #define ATTEN2DSIZE 64
805 #define ATTEN3DSIZE 32
806 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
807 for (y = 0;y < ATTEN2DSIZE;y++)
809 for (x = 0;x < ATTEN2DSIZE;x++)
811 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
812 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
814 intensity = 1.0f - sqrt(DotProduct(v, v));
816 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
817 d = (int)bound(0, intensity, 255);
818 data[(y*ATTEN2DSIZE+x)*4+0] = d;
819 data[(y*ATTEN2DSIZE+x)*4+1] = d;
820 data[(y*ATTEN2DSIZE+x)*4+2] = d;
821 data[(y*ATTEN2DSIZE+x)*4+3] = d;
824 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
825 if (r_shadow_texture3d.integer && gl_texture3d)
827 for (z = 0;z < ATTEN3DSIZE;z++)
829 for (y = 0;y < ATTEN3DSIZE;y++)
831 for (x = 0;x < ATTEN3DSIZE;x++)
833 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
834 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
835 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
836 intensity = 1.0f - sqrt(DotProduct(v, v));
838 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
839 d = (int)bound(0, intensity, 255);
840 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
841 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
842 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
843 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
847 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
852 void R_Shadow_ValidateCvars(void)
854 if (r_shadow_texture3d.integer && !gl_texture3d)
855 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
856 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
857 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
860 // light currently being rendered
861 rtlight_t *r_shadow_rtlight;
863 // this is the location of the light in entity space
864 vec3_t r_shadow_entitylightorigin;
865 // this transforms entity coordinates to light filter cubemap coordinates
866 // (also often used for other purposes)
867 matrix4x4_t r_shadow_entitytolight;
868 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
869 // of attenuation texturing in full 3D (Z result often ignored)
870 matrix4x4_t r_shadow_entitytoattenuationxyz;
871 // this transforms only the Z to S, and T is always 0.5
872 matrix4x4_t r_shadow_entitytoattenuationz;
874 void R_Shadow_RenderMode_Begin(void)
876 R_Shadow_ValidateCvars();
878 if (!r_shadow_attenuation2dtexture
879 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
880 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
881 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
882 R_Shadow_MakeTextures();
885 R_Mesh_ColorPointer(NULL);
886 R_Mesh_ResetTextureState();
887 GL_BlendFunc(GL_ONE, GL_ZERO);
889 GL_Color(0, 0, 0, 1);
890 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
892 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
894 if (gl_ext_stenciltwoside.integer)
895 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
897 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
899 if (r_glsl.integer && gl_support_fragment_shader)
900 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
901 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
902 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
904 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
907 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
909 r_shadow_rtlight = rtlight;
912 void R_Shadow_RenderMode_Reset(void)
915 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
917 qglUseProgramObjectARB(0);CHECKGLERROR
919 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
921 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
923 R_Mesh_ColorPointer(NULL);
924 R_Mesh_ResetTextureState();
927 void R_Shadow_RenderMode_StencilShadowVolumes(void)
930 R_Shadow_RenderMode_Reset();
931 GL_Color(1, 1, 1, 1);
932 GL_ColorMask(0, 0, 0, 0);
933 GL_BlendFunc(GL_ONE, GL_ZERO);
935 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
936 qglDepthFunc(GL_LESS);CHECKGLERROR
937 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
938 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
939 r_shadow_rendermode = r_shadow_shadowingrendermode;
940 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
942 GL_CullFace(GL_NONE);
943 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
944 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
945 qglStencilMask(~0);CHECKGLERROR
946 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
947 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
948 qglStencilMask(~0);CHECKGLERROR
949 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
953 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
954 qglStencilMask(~0);CHECKGLERROR
955 // this is changed by every shadow render so its value here is unimportant
956 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
958 GL_Clear(GL_STENCIL_BUFFER_BIT);
959 r_refdef.stats.lights_clears++;
962 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
965 R_Shadow_RenderMode_Reset();
966 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
968 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
969 //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
970 GL_Color(1, 1, 1, 1);
971 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
974 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
978 qglDepthFunc(GL_EQUAL);CHECKGLERROR
982 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
986 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
988 qglStencilMask(~0);CHECKGLERROR
989 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
990 // only draw light where this geometry was already rendered AND the
991 // stencil is 128 (values other than this mean shadow)
992 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
993 r_shadow_rendermode = r_shadow_lightingrendermode;
994 // do global setup needed for the chosen lighting mode
995 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
997 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
998 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
999 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1000 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1001 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1002 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1003 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1004 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1005 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1006 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1007 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1008 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1009 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1014 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1017 R_Shadow_RenderMode_Reset();
1018 GL_BlendFunc(GL_ONE, GL_ONE);
1019 GL_DepthMask(false);
1020 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1021 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1022 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1023 if (r_showshadowvolumes.integer >= 2)
1025 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
1029 qglDepthFunc(GL_GEQUAL);CHECKGLERROR
1031 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1032 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1035 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1038 R_Shadow_RenderMode_Reset();
1039 GL_BlendFunc(GL_ONE, GL_ONE);
1040 GL_DepthMask(false);
1041 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1042 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1043 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1044 if (r_showshadowvolumes.integer >= 2)
1046 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
1048 else if (transparent)
1050 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1054 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1058 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1062 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1064 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1067 void R_Shadow_RenderMode_End(void)
1070 R_Shadow_RenderMode_Reset();
1071 R_Shadow_RenderMode_ActiveLight(NULL);
1072 GL_BlendFunc(GL_ONE, GL_ZERO);
1074 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1075 //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
1076 GL_Color(1, 1, 1, 1);
1077 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1078 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1079 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1080 if (gl_support_stenciltwoside)
1082 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1084 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1085 qglStencilMask(~0);CHECKGLERROR
1086 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1087 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1088 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1089 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1092 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1094 int i, ix1, iy1, ix2, iy2;
1095 float x1, y1, x2, y2;
1098 mplane_t planes[11];
1099 float vertex3f[256*3];
1101 // if view is inside the light box, just say yes it's visible
1102 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1104 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1108 // create a temporary brush describing the area the light can affect in worldspace
1109 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1110 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1111 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1112 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1113 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1114 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1115 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1116 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1117 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1118 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1119 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1121 // turn the brush into a mesh
1122 memset(&mesh, 0, sizeof(rmesh_t));
1123 mesh.maxvertices = 256;
1124 mesh.vertex3f = vertex3f;
1125 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1126 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1128 // if that mesh is empty, the light is not visible at all
1129 if (!mesh.numvertices)
1132 if (!r_shadow_scissor.integer)
1135 // if that mesh is not empty, check what area of the screen it covers
1136 x1 = y1 = x2 = y2 = 0;
1138 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1139 for (i = 0;i < mesh.numvertices;i++)
1141 VectorCopy(mesh.vertex3f + i * 3, v);
1142 GL_TransformToScreen(v, v2);
1143 //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]);
1146 if (x1 > v2[0]) x1 = v2[0];
1147 if (x2 < v2[0]) x2 = v2[0];
1148 if (y1 > v2[1]) y1 = v2[1];
1149 if (y2 < v2[1]) y2 = v2[1];
1158 // now convert the scissor rectangle to integer screen coordinates
1159 ix1 = (int)(x1 - 1.0f);
1160 iy1 = (int)(y1 - 1.0f);
1161 ix2 = (int)(x2 + 1.0f);
1162 iy2 = (int)(y2 + 1.0f);
1163 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1165 // clamp it to the screen
1166 if (ix1 < r_view.x) ix1 = r_view.x;
1167 if (iy1 < r_view.y) iy1 = r_view.y;
1168 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1169 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1171 // if it is inside out, it's not visible
1172 if (ix2 <= ix1 || iy2 <= iy1)
1175 // the light area is visible, set up the scissor rectangle
1176 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1177 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1178 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1179 r_refdef.stats.lights_scissored++;
1183 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1185 int numverts = surface->num_vertices;
1186 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1187 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1188 float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1189 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1190 if (r_textureunits.integer >= 3)
1192 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1194 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1195 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1196 if ((dot = DotProduct(n, v)) < 0)
1198 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1199 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1200 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1201 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1202 if (r_refdef.fogenabled)
1204 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1205 VectorScale(color4f, f, color4f);
1209 VectorClear(color4f);
1213 else if (r_textureunits.integer >= 2)
1215 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1217 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1218 if ((dist = fabs(v[2])) < 1)
1220 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1221 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1222 if ((dot = DotProduct(n, v)) < 0)
1224 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1225 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1226 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1227 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1231 color4f[0] = ambientcolor[0] * distintensity;
1232 color4f[1] = ambientcolor[1] * distintensity;
1233 color4f[2] = ambientcolor[2] * distintensity;
1235 if (r_refdef.fogenabled)
1237 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1238 VectorScale(color4f, f, color4f);
1242 VectorClear(color4f);
1248 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1250 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1251 if ((dist = DotProduct(v, v)) < 1)
1254 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1255 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1256 if ((dot = DotProduct(n, v)) < 0)
1258 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1259 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1260 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1261 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1265 color4f[0] = ambientcolor[0] * distintensity;
1266 color4f[1] = ambientcolor[1] * distintensity;
1267 color4f[2] = ambientcolor[2] * distintensity;
1269 if (r_refdef.fogenabled)
1271 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1272 VectorScale(color4f, f, color4f);
1276 VectorClear(color4f);
1282 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1284 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1286 int surfacelistindex;
1287 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1289 const msurface_t *surface = surfacelist[surfacelistindex];
1291 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1292 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1293 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1294 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1295 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1297 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1299 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1300 // the cubemap normalizes this for us
1301 out3f[0] = DotProduct(svector3f, lightdir);
1302 out3f[1] = DotProduct(tvector3f, lightdir);
1303 out3f[2] = DotProduct(normal3f, lightdir);
1308 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1310 int surfacelistindex;
1311 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1313 const msurface_t *surface = surfacelist[surfacelistindex];
1315 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1316 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1317 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1318 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1319 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1320 float lightdir[3], eyedir[3], halfdir[3];
1321 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1323 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1324 VectorNormalize(lightdir);
1325 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1326 VectorNormalize(eyedir);
1327 VectorAdd(lightdir, eyedir, halfdir);
1328 // the cubemap normalizes this for us
1329 out3f[0] = DotProduct(svector3f, halfdir);
1330 out3f[1] = DotProduct(tvector3f, halfdir);
1331 out3f[2] = DotProduct(normal3f, halfdir);
1336 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)
1338 // used to display how many times a surface is lit for level design purposes
1339 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1340 R_Mesh_ColorPointer(NULL);
1341 R_Mesh_ResetTextureState();
1342 RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1343 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1344 GL_LockArrays(0, 0);
1347 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)
1349 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1350 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1351 R_SetupSurfaceShader(lightcolorbase, false);
1352 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1353 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1354 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1355 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1356 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1358 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1360 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1361 GL_LockArrays(0, 0);
1362 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1364 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1368 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1370 // shared final code for all the dot3 layers
1372 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1373 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1375 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1376 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1377 GL_LockArrays(0, 0);
1381 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1384 // colorscale accounts for how much we multiply the brightness
1387 // mult is how many times the final pass of the lighting will be
1388 // performed to get more brightness than otherwise possible.
1390 // Limit mult to 64 for sanity sake.
1392 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1394 // 3 3D combine path (Geforce3, Radeon 8500)
1395 memset(&m, 0, sizeof(m));
1396 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1397 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1398 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1399 m.tex[1] = R_GetTexture(basetexture);
1400 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1401 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1402 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1403 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1404 m.texmatrix[2] = r_shadow_entitytolight;
1405 GL_BlendFunc(GL_ONE, GL_ONE);
1407 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1409 // 2 3D combine path (Geforce3, original Radeon)
1410 memset(&m, 0, sizeof(m));
1411 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1412 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1413 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1414 m.tex[1] = R_GetTexture(basetexture);
1415 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1416 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1417 GL_BlendFunc(GL_ONE, GL_ONE);
1419 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1421 // 4 2D combine path (Geforce3, Radeon 8500)
1422 memset(&m, 0, sizeof(m));
1423 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1424 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1425 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1426 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1427 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1428 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1429 m.tex[2] = R_GetTexture(basetexture);
1430 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1431 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1432 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1434 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1435 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1436 m.texmatrix[3] = r_shadow_entitytolight;
1438 GL_BlendFunc(GL_ONE, GL_ONE);
1440 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1442 // 3 2D combine path (Geforce3, original Radeon)
1443 memset(&m, 0, sizeof(m));
1444 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1445 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1446 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1447 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1448 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1449 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1450 m.tex[2] = R_GetTexture(basetexture);
1451 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1452 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1453 GL_BlendFunc(GL_ONE, GL_ONE);
1457 // 2/2/2 2D combine path (any dot3 card)
1458 memset(&m, 0, sizeof(m));
1459 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1460 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1461 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1462 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1463 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1464 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1465 R_Mesh_TextureState(&m);
1466 GL_ColorMask(0,0,0,1);
1467 GL_BlendFunc(GL_ONE, GL_ZERO);
1468 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1469 GL_LockArrays(0, 0);
1472 memset(&m, 0, sizeof(m));
1473 m.tex[0] = R_GetTexture(basetexture);
1474 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1475 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1476 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1478 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1479 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1480 m.texmatrix[1] = r_shadow_entitytolight;
1482 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1484 // this final code is shared
1485 R_Mesh_TextureState(&m);
1486 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1489 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)
1492 // colorscale accounts for how much we multiply the brightness
1495 // mult is how many times the final pass of the lighting will be
1496 // performed to get more brightness than otherwise possible.
1498 // Limit mult to 64 for sanity sake.
1500 // generate normalization cubemap texcoords
1501 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1502 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1504 // 3/2 3D combine path (Geforce3, Radeon 8500)
1505 memset(&m, 0, sizeof(m));
1506 m.tex[0] = R_GetTexture(normalmaptexture);
1507 m.texcombinergb[0] = GL_REPLACE;
1508 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1509 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1510 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1511 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1512 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1513 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1514 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1515 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1516 R_Mesh_TextureState(&m);
1517 GL_ColorMask(0,0,0,1);
1518 GL_BlendFunc(GL_ONE, GL_ZERO);
1519 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1520 GL_LockArrays(0, 0);
1523 memset(&m, 0, sizeof(m));
1524 m.tex[0] = R_GetTexture(basetexture);
1525 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1526 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1527 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1529 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1530 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1531 m.texmatrix[1] = r_shadow_entitytolight;
1533 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1535 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1537 // 1/2/2 3D combine path (original Radeon)
1538 memset(&m, 0, sizeof(m));
1539 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1540 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1541 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1542 R_Mesh_TextureState(&m);
1543 GL_ColorMask(0,0,0,1);
1544 GL_BlendFunc(GL_ONE, GL_ZERO);
1545 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1546 GL_LockArrays(0, 0);
1549 memset(&m, 0, sizeof(m));
1550 m.tex[0] = R_GetTexture(normalmaptexture);
1551 m.texcombinergb[0] = GL_REPLACE;
1552 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1553 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1554 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1555 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1556 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1557 R_Mesh_TextureState(&m);
1558 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1559 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1560 GL_LockArrays(0, 0);
1563 memset(&m, 0, sizeof(m));
1564 m.tex[0] = R_GetTexture(basetexture);
1565 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1566 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1567 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1569 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1570 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1571 m.texmatrix[1] = r_shadow_entitytolight;
1573 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1575 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1577 // 2/2 3D combine path (original Radeon)
1578 memset(&m, 0, sizeof(m));
1579 m.tex[0] = R_GetTexture(normalmaptexture);
1580 m.texcombinergb[0] = GL_REPLACE;
1581 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1582 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1583 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1584 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1585 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1586 R_Mesh_TextureState(&m);
1587 GL_ColorMask(0,0,0,1);
1588 GL_BlendFunc(GL_ONE, GL_ZERO);
1589 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1590 GL_LockArrays(0, 0);
1593 memset(&m, 0, sizeof(m));
1594 m.tex[0] = R_GetTexture(basetexture);
1595 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1596 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1597 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1598 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1599 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1600 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1602 else if (r_textureunits.integer >= 4)
1604 // 4/2 2D combine path (Geforce3, Radeon 8500)
1605 memset(&m, 0, sizeof(m));
1606 m.tex[0] = R_GetTexture(normalmaptexture);
1607 m.texcombinergb[0] = GL_REPLACE;
1608 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1609 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1610 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1611 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1612 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1613 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1614 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1615 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1616 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1617 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1618 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1619 R_Mesh_TextureState(&m);
1620 GL_ColorMask(0,0,0,1);
1621 GL_BlendFunc(GL_ONE, GL_ZERO);
1622 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1623 GL_LockArrays(0, 0);
1626 memset(&m, 0, sizeof(m));
1627 m.tex[0] = R_GetTexture(basetexture);
1628 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1629 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1630 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1632 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1633 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1634 m.texmatrix[1] = r_shadow_entitytolight;
1636 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1640 // 2/2/2 2D combine path (any dot3 card)
1641 memset(&m, 0, sizeof(m));
1642 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1643 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1644 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1645 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1646 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1647 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1648 R_Mesh_TextureState(&m);
1649 GL_ColorMask(0,0,0,1);
1650 GL_BlendFunc(GL_ONE, GL_ZERO);
1651 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1652 GL_LockArrays(0, 0);
1655 memset(&m, 0, sizeof(m));
1656 m.tex[0] = R_GetTexture(normalmaptexture);
1657 m.texcombinergb[0] = GL_REPLACE;
1658 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1659 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1660 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1661 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1662 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1663 R_Mesh_TextureState(&m);
1664 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1665 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1666 GL_LockArrays(0, 0);
1669 memset(&m, 0, sizeof(m));
1670 m.tex[0] = R_GetTexture(basetexture);
1671 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1672 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1673 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1675 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1676 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1677 m.texmatrix[1] = r_shadow_entitytolight;
1679 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1681 // this final code is shared
1682 R_Mesh_TextureState(&m);
1683 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1686 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)
1688 float glossexponent;
1690 // FIXME: detect blendsquare!
1691 //if (!gl_support_blendsquare)
1694 // generate normalization cubemap texcoords
1695 R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1696 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1698 // 2/0/0/1/2 3D combine blendsquare path
1699 memset(&m, 0, sizeof(m));
1700 m.tex[0] = R_GetTexture(normalmaptexture);
1701 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1702 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1703 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1704 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1705 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1706 R_Mesh_TextureState(&m);
1707 GL_ColorMask(0,0,0,1);
1708 // this squares the result
1709 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1710 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1711 GL_LockArrays(0, 0);
1713 // second and third pass
1714 R_Mesh_ResetTextureState();
1715 // square alpha in framebuffer a few times to make it shiny
1716 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1717 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
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 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1766 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1767 GL_LockArrays(0, 0);
1770 memset(&m, 0, sizeof(m));
1771 m.tex[0] = R_GetTexture(glosstexture);
1772 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1773 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1774 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1775 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1776 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1777 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1781 // 2/0/0/2/2 2D combine blendsquare path
1782 memset(&m, 0, sizeof(m));
1783 m.tex[0] = R_GetTexture(normalmaptexture);
1784 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1785 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1786 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1787 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1788 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1789 R_Mesh_TextureState(&m);
1790 GL_ColorMask(0,0,0,1);
1791 // this squares the result
1792 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1793 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1794 GL_LockArrays(0, 0);
1796 // second and third pass
1797 R_Mesh_ResetTextureState();
1798 // square alpha in framebuffer a few times to make it shiny
1799 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1800 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1801 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1802 GL_LockArrays(0, 0);
1805 memset(&m, 0, sizeof(m));
1806 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1807 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1808 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1809 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1810 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1811 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1812 R_Mesh_TextureState(&m);
1813 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1814 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1815 GL_LockArrays(0, 0);
1818 memset(&m, 0, sizeof(m));
1819 m.tex[0] = R_GetTexture(glosstexture);
1820 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1821 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1822 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1824 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1825 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1826 m.texmatrix[1] = r_shadow_entitytolight;
1828 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1830 // this final code is shared
1831 R_Mesh_TextureState(&m);
1832 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1835 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)
1837 // ARB path (any Geforce, any Radeon)
1838 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1839 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1840 qboolean dospecular = specularscale > 0;
1841 if (!doambient && !dodiffuse && !dospecular)
1843 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1844 R_Mesh_ColorPointer(NULL);
1846 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1848 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1852 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1854 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1859 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1861 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1864 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1867 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1869 int surfacelistindex;
1871 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1873 const msurface_t *surface = surfacelist[surfacelistindex];
1874 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1876 for (renders = 0;renders < 64;renders++)
1882 int newnumtriangles;
1884 int newelements[3072];
1888 newnumtriangles = 0;
1890 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1892 const msurface_t *surface = surfacelist[surfacelistindex];
1893 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1895 // due to low fillrate on the cards this vertex lighting path is
1896 // designed for, we manually cull all triangles that do not
1897 // contain a lit vertex
1898 // this builds batches of triangles from multiple surfaces and
1899 // renders them at once
1900 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1902 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1904 if (newnumtriangles)
1906 firstvertex = min(firstvertex, e[0]);
1907 lastvertex = max(lastvertex, e[0]);
1914 firstvertex = min(firstvertex, e[1]);
1915 lastvertex = max(lastvertex, e[1]);
1916 firstvertex = min(firstvertex, e[2]);
1917 lastvertex = max(lastvertex, e[2]);
1923 if (newnumtriangles >= 1024)
1925 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1926 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1927 newnumtriangles = 0;
1934 if (newnumtriangles >= 1)
1936 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1937 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1940 GL_LockArrays(0, 0);
1941 // if we couldn't find any lit triangles, exit early
1944 // now reduce the intensity for the next overbright pass
1945 // we have to clamp to 0 here incase the drivers have improper
1946 // handling of negative colors
1947 // (some old drivers even have improper handling of >1 color)
1949 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1953 const msurface_t *surface = surfacelist[surfacelistindex];
1954 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1956 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1958 c[0] = max(0, c[0] - 1);
1959 c[1] = max(0, c[1] - 1);
1960 c[2] = max(0, c[2] - 1);
1973 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)
1975 // OpenGL 1.1 path (anything)
1976 model_t *model = rsurface_entity->model;
1977 float ambientcolorbase[3], diffusecolorbase[3];
1978 float ambientcolorpants[3], diffusecolorpants[3];
1979 float ambientcolorshirt[3], diffusecolorshirt[3];
1981 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
1982 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
1983 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
1984 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
1985 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
1986 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
1987 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1988 R_Mesh_ColorPointer(rsurface_array_color4f);
1989 memset(&m, 0, sizeof(m));
1990 m.tex[0] = R_GetTexture(basetexture);
1991 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1992 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1993 if (r_textureunits.integer >= 2)
1996 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1997 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1998 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1999 if (r_textureunits.integer >= 3)
2001 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2002 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2003 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2004 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2007 R_Mesh_TextureState(&m);
2008 RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
2009 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2010 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
2013 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2014 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
2018 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2019 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
2023 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
2025 // FIXME: support MATERIALFLAG_NODEPTHTEST
2026 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2027 // calculate colors to render this texture with
2028 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2029 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2030 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2031 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2033 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2034 GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2035 if (rsurface_texture->colormapping)
2037 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2038 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2041 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2042 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2043 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2046 VectorClear(lightcolorpants);
2049 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2050 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2051 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2054 VectorClear(lightcolorshirt);
2055 switch (r_shadow_rendermode)
2057 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2058 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2059 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);
2061 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2062 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);
2064 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2065 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);
2067 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2068 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);
2071 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2077 switch (r_shadow_rendermode)
2079 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2080 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2081 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);
2083 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2084 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);
2086 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2087 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);
2089 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2090 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);
2093 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2099 void R_RTLight_Update(dlight_t *light, int isstatic)
2102 rtlight_t *rtlight = &light->rtlight;
2103 R_RTLight_Uncompile(rtlight);
2104 memset(rtlight, 0, sizeof(*rtlight));
2106 VectorCopy(light->origin, rtlight->shadoworigin);
2107 VectorCopy(light->color, rtlight->color);
2108 rtlight->radius = light->radius;
2109 //rtlight->cullradius = rtlight->radius;
2110 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2111 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2112 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2113 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2114 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2115 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2116 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2117 rtlight->cubemapname[0] = 0;
2118 if (light->cubemapname[0])
2119 strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
2120 else if (light->cubemapnum > 0)
2121 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2122 rtlight->shadow = light->shadow;
2123 rtlight->corona = light->corona;
2124 rtlight->style = light->style;
2125 rtlight->isstatic = isstatic;
2126 rtlight->coronasizescale = light->coronasizescale;
2127 rtlight->ambientscale = light->ambientscale;
2128 rtlight->diffusescale = light->diffusescale;
2129 rtlight->specularscale = light->specularscale;
2130 rtlight->flags = light->flags;
2131 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2132 // this has to scale both rotate and translate because this is an already
2133 // inverted matrix (it transforms from world to light space, not the other
2135 scale = 1.0 / rtlight->radius;
2136 Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
2139 // compiles rtlight geometry
2140 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2141 void R_RTLight_Compile(rtlight_t *rtlight)
2143 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2144 entity_render_t *ent = r_refdef.worldentity;
2145 model_t *model = r_refdef.worldmodel;
2146 unsigned char *data;
2148 // compile the light
2149 rtlight->compiled = true;
2150 rtlight->static_numleafs = 0;
2151 rtlight->static_numleafpvsbytes = 0;
2152 rtlight->static_leaflist = NULL;
2153 rtlight->static_leafpvs = NULL;
2154 rtlight->static_numsurfaces = 0;
2155 rtlight->static_surfacelist = NULL;
2156 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2157 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2158 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2159 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2160 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2161 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2163 if (model && model->GetLightInfo)
2165 // this variable must be set for the CompileShadowVolume code
2166 r_shadow_compilingrtlight = rtlight;
2167 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2168 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);
2169 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2170 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2171 rtlight->static_numleafs = numleafs;
2172 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2173 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2174 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2175 rtlight->static_numsurfaces = numsurfaces;
2176 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2178 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2179 if (numleafpvsbytes)
2180 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2182 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2183 if (model->CompileShadowVolume && rtlight->shadow)
2184 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2185 // now we're done compiling the rtlight
2186 r_shadow_compilingrtlight = NULL;
2190 // use smallest available cullradius - box radius or light radius
2191 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2192 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2196 if (rtlight->static_meshchain_shadow)
2199 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2202 shadowtris += mesh->numtriangles;
2206 if (developer.integer >= 10)
2207 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);
2210 void R_RTLight_Uncompile(rtlight_t *rtlight)
2212 if (rtlight->compiled)
2214 if (rtlight->static_meshchain_shadow)
2215 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2216 rtlight->static_meshchain_shadow = NULL;
2217 // these allocations are grouped
2218 if (rtlight->static_leaflist)
2219 Mem_Free(rtlight->static_leaflist);
2220 rtlight->static_numleafs = 0;
2221 rtlight->static_numleafpvsbytes = 0;
2222 rtlight->static_leaflist = NULL;
2223 rtlight->static_leafpvs = NULL;
2224 rtlight->static_numsurfaces = 0;
2225 rtlight->static_surfacelist = NULL;
2226 rtlight->compiled = false;
2230 void R_Shadow_UncompileWorldLights(void)
2233 for (light = r_shadow_worldlightchain;light;light = light->next)
2234 R_RTLight_Uncompile(&light->rtlight);
2237 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2239 model_t *model = ent->model;
2240 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2241 vec_t relativeshadowradius;
2242 if (ent == r_refdef.worldentity)
2244 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2247 R_Mesh_Matrix(&ent->matrix);
2249 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2251 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2252 R_Mesh_VertexPointer(mesh->vertex3f);
2253 GL_LockArrays(0, mesh->numverts);
2254 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2256 // decrement stencil if backface is behind depthbuffer
2257 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2258 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2259 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2260 // increment stencil if frontface is behind depthbuffer
2261 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2262 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2264 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2265 GL_LockArrays(0, 0);
2269 else if (numsurfaces)
2271 R_Mesh_Matrix(&ent->matrix);
2272 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2277 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2278 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2279 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2280 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2281 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2282 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2283 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2284 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2285 R_Mesh_Matrix(&ent->matrix);
2286 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2290 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2292 // set up properties for rendering light onto this entity
2293 RSurf_ActiveEntity(ent, true, true);
2294 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2295 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2296 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2297 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2298 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2299 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2302 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2304 model_t *model = ent->model;
2305 if (!model->DrawLight)
2307 R_Shadow_SetupEntityLight(ent);
2308 if (ent == r_refdef.worldentity)
2309 model->DrawLight(ent, numsurfaces, surfacelist);
2311 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2314 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2318 int numleafs, numsurfaces;
2319 int *leaflist, *surfacelist;
2320 unsigned char *leafpvs;
2321 int numlightentities;
2322 int numshadowentities;
2323 entity_render_t *lightentities[MAX_EDICTS];
2324 entity_render_t *shadowentities[MAX_EDICTS];
2326 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2327 // skip lights that are basically invisible (color 0 0 0)
2328 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2331 // loading is done before visibility checks because loading should happen
2332 // all at once at the start of a level, not when it stalls gameplay.
2333 // (especially important to benchmarks)
2335 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2336 R_RTLight_Compile(rtlight);
2338 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2340 // look up the light style value at this time
2341 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2342 VectorScale(rtlight->color, f, rtlight->currentcolor);
2344 if (rtlight->selected)
2346 f = 2 + sin(realtime * M_PI * 4.0);
2347 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2351 // if lightstyle is currently off, don't draw the light
2352 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2355 // if the light box is offscreen, skip it
2356 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2359 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2361 // compiled light, world available and can receive realtime lighting
2362 // retrieve leaf information
2363 numleafs = rtlight->static_numleafs;
2364 leaflist = rtlight->static_leaflist;
2365 leafpvs = rtlight->static_leafpvs;
2366 numsurfaces = rtlight->static_numsurfaces;
2367 surfacelist = rtlight->static_surfacelist;
2369 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2371 // dynamic light, world available and can receive realtime lighting
2372 // calculate lit surfaces and leafs
2373 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2374 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);
2375 leaflist = r_shadow_buffer_leaflist;
2376 leafpvs = r_shadow_buffer_leafpvs;
2377 surfacelist = r_shadow_buffer_surfacelist;
2378 // if the reduced leaf bounds are offscreen, skip it
2379 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2391 // check if light is illuminating any visible leafs
2394 for (i = 0;i < numleafs;i++)
2395 if (r_viewcache.world_leafvisible[leaflist[i]])
2400 // set up a scissor rectangle for this light
2401 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2404 // make a list of lit entities and shadow casting entities
2405 numlightentities = 0;
2406 numshadowentities = 0;
2407 // don't count the world unless some surfaces are actually lit
2410 lightentities[numlightentities++] = r_refdef.worldentity;
2411 shadowentities[numshadowentities++] = r_refdef.worldentity;
2413 // add dynamic entities that are lit by the light
2414 if (r_drawentities.integer)
2416 for (i = 0;i < r_refdef.numentities;i++)
2419 entity_render_t *ent = r_refdef.entities[i];
2420 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2421 && (model = ent->model)
2422 && !(ent->flags & RENDER_TRANSPARENT)
2423 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2425 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2427 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2428 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2429 shadowentities[numshadowentities++] = ent;
2430 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2431 lightentities[numlightentities++] = ent;
2436 // return if there's nothing at all to light
2437 if (!numlightentities)
2440 // don't let sound skip if going slow
2441 if (r_refdef.extraupdate)
2444 // make this the active rtlight for rendering purposes
2445 R_Shadow_RenderMode_ActiveLight(rtlight);
2446 // count this light in the r_speeds
2447 r_refdef.stats.lights++;
2450 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2452 // draw stencil shadow volumes to mask off pixels that are in shadow
2453 // so that they won't receive lighting
2457 R_Shadow_RenderMode_StencilShadowVolumes();
2458 for (i = 0;i < numshadowentities;i++)
2459 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2462 // optionally draw visible shape of the shadow volumes
2463 // for performance analysis by level designers
2464 if (r_showshadowvolumes.integer)
2466 R_Shadow_RenderMode_VisibleShadowVolumes();
2467 for (i = 0;i < numshadowentities;i++)
2468 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2472 if (numlightentities)
2474 // draw lighting in the unmasked areas
2475 R_Shadow_RenderMode_Lighting(usestencil, false);
2476 for (i = 0;i < numlightentities;i++)
2477 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2479 // optionally draw the illuminated areas
2480 // for performance analysis by level designers
2481 if (r_showlighting.integer)
2483 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2484 for (i = 0;i < numlightentities;i++)
2485 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2490 void R_ShadowVolumeLighting(qboolean visible)
2495 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2496 R_Shadow_EditLights_Reload_f();
2498 R_Shadow_RenderMode_Begin();
2500 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2501 if (r_shadow_debuglight.integer >= 0)
2503 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2504 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2505 R_DrawRTLight(&light->rtlight, visible);
2508 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2509 if (light->flags & flag)
2510 R_DrawRTLight(&light->rtlight, visible);
2511 if (r_refdef.rtdlight)
2512 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2513 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2515 R_Shadow_RenderMode_End();
2518 extern void R_SetupView(const matrix4x4_t *matrix);
2519 extern cvar_t r_shadows_throwdistance;
2520 void R_DrawModelShadows(void)
2523 float relativethrowdistance;
2524 entity_render_t *ent;
2525 vec3_t relativelightorigin;
2526 vec3_t relativelightdirection;
2527 vec3_t relativeshadowmins, relativeshadowmaxs;
2530 if (!r_drawentities.integer || !gl_stencil)
2534 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2536 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2538 if (gl_ext_stenciltwoside.integer)
2539 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2541 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2543 R_Shadow_RenderMode_StencilShadowVolumes();
2545 for (i = 0;i < r_refdef.numentities;i++)
2547 ent = r_refdef.entities[i];
2548 // cast shadows from anything that is not a submodel of the map
2549 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2551 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2552 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2553 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2554 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2555 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2556 R_Mesh_Matrix(&ent->matrix);
2557 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2561 // not really the right mode, but this will disable any silly stencil features
2562 R_Shadow_RenderMode_VisibleLighting(true, true);
2564 // vertex coordinates for a quad that covers the screen exactly
2565 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2566 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2567 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2568 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2570 // set up ortho view for rendering this pass
2571 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2572 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2573 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2574 GL_ScissorTest(true);
2575 R_Mesh_Matrix(&identitymatrix);
2576 R_Mesh_ResetTextureState();
2577 R_Mesh_VertexPointer(vertex3f);
2578 R_Mesh_ColorPointer(NULL);
2580 // set up a 50% darkening blend on shadowed areas
2581 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2582 GL_DepthTest(false);
2583 GL_DepthMask(false);
2584 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2585 GL_Color(0, 0, 0, 0.5);
2586 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2587 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2588 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2589 qglStencilMask(~0);CHECKGLERROR
2590 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2591 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2593 // apply the blend to the shadowed areas
2594 R_Mesh_Draw(0, 4, 2, polygonelements);
2596 // restore perspective view
2597 R_SetupView(&r_view.matrix);
2599 // restore other state to normal
2601 R_Shadow_RenderMode_End();
2605 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2606 typedef struct suffixinfo_s
2609 qboolean flipx, flipy, flipdiagonal;
2612 static suffixinfo_t suffix[3][6] =
2615 {"px", false, false, false},
2616 {"nx", false, false, false},
2617 {"py", false, false, false},
2618 {"ny", false, false, false},
2619 {"pz", false, false, false},
2620 {"nz", false, false, false}
2623 {"posx", false, false, false},
2624 {"negx", false, false, false},
2625 {"posy", false, false, false},
2626 {"negy", false, false, false},
2627 {"posz", false, false, false},
2628 {"negz", false, false, false}
2631 {"rt", true, false, true},
2632 {"lf", false, true, true},
2633 {"ft", true, true, false},
2634 {"bk", false, false, false},
2635 {"up", true, false, true},
2636 {"dn", true, false, true}
2640 static int componentorder[4] = {0, 1, 2, 3};
2642 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2644 int i, j, cubemapsize;
2645 unsigned char *cubemappixels, *image_rgba;
2646 rtexture_t *cubemaptexture;
2648 // must start 0 so the first loadimagepixels has no requested width/height
2650 cubemappixels = NULL;
2651 cubemaptexture = NULL;
2652 // keep trying different suffix groups (posx, px, rt) until one loads
2653 for (j = 0;j < 3 && !cubemappixels;j++)
2655 // load the 6 images in the suffix group
2656 for (i = 0;i < 6;i++)
2658 // generate an image name based on the base and and suffix
2659 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2661 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2663 // an image loaded, make sure width and height are equal
2664 if (image_width == image_height)
2666 // if this is the first image to load successfully, allocate the cubemap memory
2667 if (!cubemappixels && image_width >= 1)
2669 cubemapsize = image_width;
2670 // note this clears to black, so unavailable sides are black
2671 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2673 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2675 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);
2678 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2680 Mem_Free(image_rgba);
2684 // if a cubemap loaded, upload it
2687 if (!r_shadow_filters_texturepool)
2688 r_shadow_filters_texturepool = R_AllocTexturePool();
2689 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2690 Mem_Free(cubemappixels);
2694 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2695 for (j = 0;j < 3;j++)
2696 for (i = 0;i < 6;i++)
2697 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2698 Con_Print(" and was unable to find any of them.\n");
2700 return cubemaptexture;
2703 rtexture_t *R_Shadow_Cubemap(const char *basename)
2706 for (i = 0;i < numcubemaps;i++)
2707 if (!strcasecmp(cubemaps[i].basename, basename))
2708 return cubemaps[i].texture;
2709 if (i >= MAX_CUBEMAPS)
2710 return r_texture_whitecube;
2712 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2713 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2714 if (!cubemaps[i].texture)
2715 cubemaps[i].texture = r_texture_whitecube;
2716 return cubemaps[i].texture;
2719 void R_Shadow_FreeCubemaps(void)
2722 R_FreeTexturePool(&r_shadow_filters_texturepool);
2725 dlight_t *R_Shadow_NewWorldLight(void)
2728 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2729 light->next = r_shadow_worldlightchain;
2730 r_shadow_worldlightchain = light;
2734 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)
2736 VectorCopy(origin, light->origin);
2737 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2738 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2739 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2740 light->color[0] = max(color[0], 0);
2741 light->color[1] = max(color[1], 0);
2742 light->color[2] = max(color[2], 0);
2743 light->radius = max(radius, 0);
2744 light->style = style;
2745 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2747 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2750 light->shadow = shadowenable;
2751 light->corona = corona;
2754 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2755 light->coronasizescale = coronasizescale;
2756 light->ambientscale = ambientscale;
2757 light->diffusescale = diffusescale;
2758 light->specularscale = specularscale;
2759 light->flags = flags;
2760 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2762 R_RTLight_Update(light, true);
2765 void R_Shadow_FreeWorldLight(dlight_t *light)
2767 dlight_t **lightpointer;
2768 R_RTLight_Uncompile(&light->rtlight);
2769 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2770 if (*lightpointer != light)
2771 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2772 *lightpointer = light->next;
2776 void R_Shadow_ClearWorldLights(void)
2778 while (r_shadow_worldlightchain)
2779 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2780 r_shadow_selectedlight = NULL;
2781 R_Shadow_FreeCubemaps();
2784 void R_Shadow_SelectLight(dlight_t *light)
2786 if (r_shadow_selectedlight)
2787 r_shadow_selectedlight->selected = false;
2788 r_shadow_selectedlight = light;
2789 if (r_shadow_selectedlight)
2790 r_shadow_selectedlight->selected = true;
2793 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2795 // this is never batched (there can be only one)
2796 float scale = r_editlights_cursorgrid.value * 0.5f;
2797 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);
2800 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2802 // this is never batched (due to the ent parameter changing every time)
2803 // so numsurfaces == 1 and surfacelist[0] == lightnumber
2805 const dlight_t *light = (dlight_t *)ent;
2807 if (light->selected)
2808 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2811 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);
2814 void R_Shadow_DrawLightSprites(void)
2819 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2820 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2821 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2824 void R_Shadow_SelectLightInView(void)
2826 float bestrating, rating, temp[3];
2827 dlight_t *best, *light;
2830 for (light = r_shadow_worldlightchain;light;light = light->next)
2832 VectorSubtract(light->origin, r_view.origin, temp);
2833 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2836 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2837 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2839 bestrating = rating;
2844 R_Shadow_SelectLight(best);
2847 void R_Shadow_LoadWorldLights(void)
2849 int n, a, style, shadow, flags;
2850 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2851 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2852 if (r_refdef.worldmodel == NULL)
2854 Con_Print("No map loaded.\n");
2857 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2858 strlcat (name, ".rtlights", sizeof (name));
2859 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2869 for (;COM_Parse(t, true) && strcmp(
2870 if (COM_Parse(t, true))
2872 if (com_token[0] == '!')
2875 origin[0] = atof(com_token+1);
2878 origin[0] = atof(com_token);
2883 while (*s && *s != '\n' && *s != '\r')
2889 // check for modifier flags
2896 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);
2899 flags = LIGHTFLAG_REALTIMEMODE;
2907 coronasizescale = 0.25f;
2909 VectorClear(angles);
2912 if (a < 9 || !strcmp(cubemapname, "\"\""))
2914 // remove quotes on cubemapname
2915 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2918 namelen = strlen(cubemapname) - 2;
2919 memmove(cubemapname, cubemapname + 1, namelen);
2920 cubemapname[namelen] = '\0';
2924 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);
2927 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2935 Con_Printf("invalid rtlights file \"%s\"\n", name);
2936 Mem_Free(lightsstring);
2940 void R_Shadow_SaveWorldLights(void)
2943 size_t bufchars, bufmaxchars;
2945 char name[MAX_QPATH];
2946 char line[MAX_INPUTLINE];
2947 if (!r_shadow_worldlightchain)
2949 if (r_refdef.worldmodel == NULL)
2951 Con_Print("No map loaded.\n");
2954 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2955 strlcat (name, ".rtlights", sizeof (name));
2956 bufchars = bufmaxchars = 0;
2958 for (light = r_shadow_worldlightchain;light;light = light->next)
2960 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2961 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);
2962 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2963 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]);
2965 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);
2966 if (bufchars + strlen(line) > bufmaxchars)
2968 bufmaxchars = bufchars + strlen(line) + 2048;
2970 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2974 memcpy(buf, oldbuf, bufchars);
2980 memcpy(buf + bufchars, line, strlen(line));
2981 bufchars += strlen(line);
2985 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2990 void R_Shadow_LoadLightsFile(void)
2993 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
2994 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2995 if (r_refdef.worldmodel == NULL)
2997 Con_Print("No map loaded.\n");
3000 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3001 strlcat (name, ".lights", sizeof (name));
3002 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3010 while (*s && *s != '\n' && *s != '\r')
3016 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);
3020 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);
3023 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3024 radius = bound(15, radius, 4096);
3025 VectorScale(color, (2.0f / (8388608.0f)), color);
3026 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3034 Con_Printf("invalid lights file \"%s\"\n", name);
3035 Mem_Free(lightsstring);
3039 // tyrlite/hmap2 light types in the delay field
3040 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3042 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3044 int entnum, style, islight, skin, pflags, effects, type, n;
3047 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3048 char key[256], value[MAX_INPUTLINE];
3050 if (r_refdef.worldmodel == NULL)
3052 Con_Print("No map loaded.\n");
3055 // try to load a .ent file first
3056 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3057 strlcat (key, ".ent", sizeof (key));
3058 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3059 // and if that is not found, fall back to the bsp file entity string
3061 data = r_refdef.worldmodel->brush.entities;
3064 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3066 type = LIGHTTYPE_MINUSX;
3067 origin[0] = origin[1] = origin[2] = 0;
3068 originhack[0] = originhack[1] = originhack[2] = 0;
3069 angles[0] = angles[1] = angles[2] = 0;
3070 color[0] = color[1] = color[2] = 1;
3071 light[0] = light[1] = light[2] = 1;light[3] = 300;
3072 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3082 if (!COM_ParseTokenConsole(&data))
3084 if (com_token[0] == '}')
3085 break; // end of entity
3086 if (com_token[0] == '_')
3087 strlcpy(key, com_token + 1, sizeof(key));
3089 strlcpy(key, com_token, sizeof(key));
3090 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3091 key[strlen(key)-1] = 0;
3092 if (!COM_ParseTokenConsole(&data))
3094 strlcpy(value, com_token, sizeof(value));
3096 // now that we have the key pair worked out...
3097 if (!strcmp("light", key))
3099 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3103 light[0] = vec[0] * (1.0f / 256.0f);
3104 light[1] = vec[0] * (1.0f / 256.0f);
3105 light[2] = vec[0] * (1.0f / 256.0f);
3111 light[0] = vec[0] * (1.0f / 255.0f);
3112 light[1] = vec[1] * (1.0f / 255.0f);
3113 light[2] = vec[2] * (1.0f / 255.0f);
3117 else if (!strcmp("delay", key))
3119 else if (!strcmp("origin", key))
3120 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3121 else if (!strcmp("angle", key))
3122 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3123 else if (!strcmp("angles", key))
3124 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3125 else if (!strcmp("color", key))
3126 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3127 else if (!strcmp("wait", key))
3128 fadescale = atof(value);
3129 else if (!strcmp("classname", key))
3131 if (!strncmp(value, "light", 5))
3134 if (!strcmp(value, "light_fluoro"))
3139 overridecolor[0] = 1;
3140 overridecolor[1] = 1;
3141 overridecolor[2] = 1;
3143 if (!strcmp(value, "light_fluorospark"))
3148 overridecolor[0] = 1;
3149 overridecolor[1] = 1;
3150 overridecolor[2] = 1;
3152 if (!strcmp(value, "light_globe"))
3157 overridecolor[0] = 1;
3158 overridecolor[1] = 0.8;
3159 overridecolor[2] = 0.4;
3161 if (!strcmp(value, "light_flame_large_yellow"))
3166 overridecolor[0] = 1;
3167 overridecolor[1] = 0.5;
3168 overridecolor[2] = 0.1;
3170 if (!strcmp(value, "light_flame_small_yellow"))
3175 overridecolor[0] = 1;
3176 overridecolor[1] = 0.5;
3177 overridecolor[2] = 0.1;
3179 if (!strcmp(value, "light_torch_small_white"))
3184 overridecolor[0] = 1;
3185 overridecolor[1] = 0.5;
3186 overridecolor[2] = 0.1;
3188 if (!strcmp(value, "light_torch_small_walltorch"))
3193 overridecolor[0] = 1;
3194 overridecolor[1] = 0.5;
3195 overridecolor[2] = 0.1;
3199 else if (!strcmp("style", key))
3200 style = atoi(value);
3201 else if (!strcmp("skin", key))
3202 skin = (int)atof(value);
3203 else if (!strcmp("pflags", key))
3204 pflags = (int)atof(value);
3205 else if (!strcmp("effects", key))
3206 effects = (int)atof(value);
3207 else if (r_refdef.worldmodel->type == mod_brushq3)
3209 if (!strcmp("scale", key))
3210 lightscale = atof(value);
3211 if (!strcmp("fade", key))
3212 fadescale = atof(value);
3217 if (lightscale <= 0)
3221 if (color[0] == color[1] && color[0] == color[2])
3223 color[0] *= overridecolor[0];
3224 color[1] *= overridecolor[1];
3225 color[2] *= overridecolor[2];
3227 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3228 color[0] = color[0] * light[0];
3229 color[1] = color[1] * light[1];
3230 color[2] = color[2] * light[2];
3233 case LIGHTTYPE_MINUSX:
3235 case LIGHTTYPE_RECIPX:
3237 VectorScale(color, (1.0f / 16.0f), color);
3239 case LIGHTTYPE_RECIPXX:
3241 VectorScale(color, (1.0f / 16.0f), color);
3244 case LIGHTTYPE_NONE:
3248 case LIGHTTYPE_MINUSXX:
3251 VectorAdd(origin, originhack, origin);
3253 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);
3256 Mem_Free(entfiledata);
3260 void R_Shadow_SetCursorLocationForView(void)
3263 vec3_t dest, endpos;
3265 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3266 trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3267 if (trace.fraction < 1)
3269 dist = trace.fraction * r_editlights_cursordistance.value;
3270 push = r_editlights_cursorpushback.value;
3274 VectorMA(trace.endpos, push, r_view.forward, endpos);
3275 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3279 VectorClear( endpos );
3281 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3282 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3283 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3286 void R_Shadow_UpdateWorldLightSelection(void)
3288 if (r_editlights.integer)
3290 R_Shadow_SetCursorLocationForView();
3291 R_Shadow_SelectLightInView();
3292 R_Shadow_DrawLightSprites();
3295 R_Shadow_SelectLight(NULL);
3298 void R_Shadow_EditLights_Clear_f(void)
3300 R_Shadow_ClearWorldLights();
3303 void R_Shadow_EditLights_Reload_f(void)
3305 if (!r_refdef.worldmodel)
3307 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3308 R_Shadow_ClearWorldLights();
3309 R_Shadow_LoadWorldLights();
3310 if (r_shadow_worldlightchain == NULL)
3312 R_Shadow_LoadLightsFile();
3313 if (r_shadow_worldlightchain == NULL)
3314 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3318 void R_Shadow_EditLights_Save_f(void)
3320 if (!r_refdef.worldmodel)
3322 R_Shadow_SaveWorldLights();
3325 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3327 R_Shadow_ClearWorldLights();
3328 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3331 void R_Shadow_EditLights_ImportLightsFile_f(void)
3333 R_Shadow_ClearWorldLights();
3334 R_Shadow_LoadLightsFile();
3337 void R_Shadow_EditLights_Spawn_f(void)
3340 if (!r_editlights.integer)
3342 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3345 if (Cmd_Argc() != 1)
3347 Con_Print("r_editlights_spawn does not take parameters\n");
3350 color[0] = color[1] = color[2] = 1;
3351 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3354 void R_Shadow_EditLights_Edit_f(void)
3356 vec3_t origin, angles, color;
3357 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3358 int style, shadows, flags, normalmode, realtimemode;
3359 char cubemapname[MAX_INPUTLINE];
3360 if (!r_editlights.integer)
3362 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3365 if (!r_shadow_selectedlight)
3367 Con_Print("No selected light.\n");
3370 VectorCopy(r_shadow_selectedlight->origin, origin);
3371 VectorCopy(r_shadow_selectedlight->angles, angles);
3372 VectorCopy(r_shadow_selectedlight->color, color);
3373 radius = r_shadow_selectedlight->radius;
3374 style = r_shadow_selectedlight->style;
3375 if (r_shadow_selectedlight->cubemapname)
3376 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3379 shadows = r_shadow_selectedlight->shadow;
3380 corona = r_shadow_selectedlight->corona;
3381 coronasizescale = r_shadow_selectedlight->coronasizescale;
3382 ambientscale = r_shadow_selectedlight->ambientscale;
3383 diffusescale = r_shadow_selectedlight->diffusescale;
3384 specularscale = r_shadow_selectedlight->specularscale;
3385 flags = r_shadow_selectedlight->flags;
3386 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3387 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3388 if (!strcmp(Cmd_Argv(1), "origin"))
3390 if (Cmd_Argc() != 5)
3392 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3395 origin[0] = atof(Cmd_Argv(2));
3396 origin[1] = atof(Cmd_Argv(3));
3397 origin[2] = atof(Cmd_Argv(4));
3399 else if (!strcmp(Cmd_Argv(1), "originx"))
3401 if (Cmd_Argc() != 3)
3403 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3406 origin[0] = atof(Cmd_Argv(2));
3408 else if (!strcmp(Cmd_Argv(1), "originy"))
3410 if (Cmd_Argc() != 3)
3412 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3415 origin[1] = atof(Cmd_Argv(2));
3417 else if (!strcmp(Cmd_Argv(1), "originz"))
3419 if (Cmd_Argc() != 3)
3421 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3424 origin[2] = atof(Cmd_Argv(2));
3426 else if (!strcmp(Cmd_Argv(1), "move"))
3428 if (Cmd_Argc() != 5)
3430 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3433 origin[0] += atof(Cmd_Argv(2));
3434 origin[1] += atof(Cmd_Argv(3));
3435 origin[2] += atof(Cmd_Argv(4));
3437 else if (!strcmp(Cmd_Argv(1), "movex"))
3439 if (Cmd_Argc() != 3)
3441 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3444 origin[0] += atof(Cmd_Argv(2));
3446 else if (!strcmp(Cmd_Argv(1), "movey"))
3448 if (Cmd_Argc() != 3)
3450 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3453 origin[1] += atof(Cmd_Argv(2));
3455 else if (!strcmp(Cmd_Argv(1), "movez"))
3457 if (Cmd_Argc() != 3)
3459 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3462 origin[2] += atof(Cmd_Argv(2));
3464 else if (!strcmp(Cmd_Argv(1), "angles"))
3466 if (Cmd_Argc() != 5)
3468 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3471 angles[0] = atof(Cmd_Argv(2));
3472 angles[1] = atof(Cmd_Argv(3));
3473 angles[2] = atof(Cmd_Argv(4));
3475 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3477 if (Cmd_Argc() != 3)
3479 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3482 angles[0] = atof(Cmd_Argv(2));
3484 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3486 if (Cmd_Argc() != 3)
3488 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3491 angles[1] = atof(Cmd_Argv(2));
3493 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3495 if (Cmd_Argc() != 3)
3497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3500 angles[2] = atof(Cmd_Argv(2));
3502 else if (!strcmp(Cmd_Argv(1), "color"))
3504 if (Cmd_Argc() != 5)
3506 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3509 color[0] = atof(Cmd_Argv(2));
3510 color[1] = atof(Cmd_Argv(3));
3511 color[2] = atof(Cmd_Argv(4));
3513 else if (!strcmp(Cmd_Argv(1), "radius"))
3515 if (Cmd_Argc() != 3)
3517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3520 radius = atof(Cmd_Argv(2));
3522 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3524 if (Cmd_Argc() == 3)
3526 double scale = atof(Cmd_Argv(2));
3533 if (Cmd_Argc() != 5)
3535 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3538 color[0] *= atof(Cmd_Argv(2));
3539 color[1] *= atof(Cmd_Argv(3));
3540 color[2] *= atof(Cmd_Argv(4));
3543 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3545 if (Cmd_Argc() != 3)
3547 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3550 radius *= atof(Cmd_Argv(2));
3552 else if (!strcmp(Cmd_Argv(1), "style"))
3554 if (Cmd_Argc() != 3)
3556 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3559 style = atoi(Cmd_Argv(2));
3561 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3565 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3568 if (Cmd_Argc() == 3)
3569 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3573 else if (!strcmp(Cmd_Argv(1), "shadows"))
3575 if (Cmd_Argc() != 3)
3577 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3580 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3582 else if (!strcmp(Cmd_Argv(1), "corona"))
3584 if (Cmd_Argc() != 3)
3586 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3589 corona = atof(Cmd_Argv(2));
3591 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3593 if (Cmd_Argc() != 3)
3595 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3598 coronasizescale = atof(Cmd_Argv(2));
3600 else if (!strcmp(Cmd_Argv(1), "ambient"))
3602 if (Cmd_Argc() != 3)
3604 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3607 ambientscale = atof(Cmd_Argv(2));
3609 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3611 if (Cmd_Argc() != 3)
3613 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3616 diffusescale = atof(Cmd_Argv(2));
3618 else if (!strcmp(Cmd_Argv(1), "specular"))
3620 if (Cmd_Argc() != 3)
3622 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3625 specularscale = atof(Cmd_Argv(2));
3627 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3629 if (Cmd_Argc() != 3)
3631 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3634 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3636 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3638 if (Cmd_Argc() != 3)
3640 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3643 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3647 Con_Print("usage: r_editlights_edit [property] [value]\n");
3648 Con_Print("Selected light's properties:\n");
3649 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3650 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3651 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3652 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3653 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3654 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3655 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3656 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3657 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3658 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3659 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3660 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3661 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3662 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3665 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3666 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3669 void R_Shadow_EditLights_EditAll_f(void)
3673 if (!r_editlights.integer)
3675 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3679 for (light = r_shadow_worldlightchain;light;light = light->next)
3681 R_Shadow_SelectLight(light);
3682 R_Shadow_EditLights_Edit_f();
3686 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3688 int lightnumber, lightcount;
3692 if (!r_editlights.integer)
3698 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3699 if (light == r_shadow_selectedlight)
3700 lightnumber = lightcount;
3701 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;
3702 if (r_shadow_selectedlight == NULL)
3704 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3705 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;
3706 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;
3707 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;
3708 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3709 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3710 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3711 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;
3712 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3713 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3714 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3715 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3716 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3717 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;
3718 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;
3721 void R_Shadow_EditLights_ToggleShadow_f(void)
3723 if (!r_editlights.integer)
3725 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3728 if (!r_shadow_selectedlight)
3730 Con_Print("No selected light.\n");
3733 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);
3736 void R_Shadow_EditLights_ToggleCorona_f(void)
3738 if (!r_editlights.integer)
3740 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3743 if (!r_shadow_selectedlight)
3745 Con_Print("No selected light.\n");
3748 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);
3751 void R_Shadow_EditLights_Remove_f(void)
3753 if (!r_editlights.integer)
3755 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3758 if (!r_shadow_selectedlight)
3760 Con_Print("No selected light.\n");
3763 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3764 r_shadow_selectedlight = NULL;
3767 void R_Shadow_EditLights_Help_f(void)
3770 "Documentation on r_editlights system:\n"
3772 "r_editlights : enable/disable editing mode\n"
3773 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3774 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3775 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3776 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3777 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3779 "r_editlights_help : this help\n"
3780 "r_editlights_clear : remove all lights\n"
3781 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3782 "r_editlights_save : save to .rtlights file\n"
3783 "r_editlights_spawn : create a light with default settings\n"
3784 "r_editlights_edit command : edit selected light - more documentation below\n"
3785 "r_editlights_remove : remove selected light\n"
3786 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3787 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3788 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3790 "origin x y z : set light location\n"
3791 "originx x: set x component of light location\n"
3792 "originy y: set y component of light location\n"
3793 "originz z: set z component of light location\n"
3794 "move x y z : adjust light location\n"
3795 "movex x: adjust x component of light location\n"
3796 "movey y: adjust y component of light location\n"
3797 "movez z: adjust z component of light location\n"
3798 "angles x y z : set light angles\n"
3799 "anglesx x: set x component of light angles\n"
3800 "anglesy y: set y component of light angles\n"
3801 "anglesz z: set z component of light angles\n"
3802 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3803 "radius radius : set radius (size) of light\n"
3804 "colorscale grey : multiply color of light (1 does nothing)\n"
3805 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3806 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3807 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3808 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3809 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3810 "shadows 1/0 : turn on/off shadows\n"
3811 "corona n : set corona intensity\n"
3812 "coronasize n : set corona size (0-1)\n"
3813 "ambient n : set ambient intensity (0-1)\n"
3814 "diffuse n : set diffuse intensity (0-1)\n"
3815 "specular n : set specular intensity (0-1)\n"
3816 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3817 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3818 "<nothing> : print light properties to console\n"
3822 void R_Shadow_EditLights_CopyInfo_f(void)
3824 if (!r_editlights.integer)
3826 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3829 if (!r_shadow_selectedlight)
3831 Con_Print("No selected light.\n");
3834 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3835 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3836 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3837 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3838 if (r_shadow_selectedlight->cubemapname)
3839 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3841 r_shadow_bufferlight.cubemapname[0] = 0;
3842 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3843 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3844 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3845 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3846 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3847 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3848 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3851 void R_Shadow_EditLights_PasteInfo_f(void)
3853 if (!r_editlights.integer)
3855 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3858 if (!r_shadow_selectedlight)
3860 Con_Print("No selected light.\n");
3863 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);
3866 void R_Shadow_EditLights_Init(void)
3868 Cvar_RegisterVariable(&r_editlights);
3869 Cvar_RegisterVariable(&r_editlights_cursordistance);
3870 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3871 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3872 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3873 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3874 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3875 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3876 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)");
3877 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3878 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3879 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3880 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)");
3881 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3882 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3883 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3884 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3885 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3886 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3887 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)");